From 05af380f63b8a72a45a3a724da1cefe9bd5c235c Mon Sep 17 00:00:00 2001 From: Pascal Packaging Team Date: Sat, 14 Apr 2018 17:08:39 +0100 Subject: [PATCH] add-arm64-support Gbp-Pq: Name add-arm64-support.patch --- fpcsrc/Makefile.fpc | 3 + fpcsrc/compiler/Makefile.fpc | 14 +- fpcsrc/compiler/aarch64/a64att.inc | 131 +- fpcsrc/compiler/aarch64/a64atts.inc | 59 +- fpcsrc/compiler/aarch64/a64ins.dat | 202 +- fpcsrc/compiler/aarch64/a64op.inc | 131 +- fpcsrc/compiler/aarch64/a64reg.dat | 329 +- fpcsrc/compiler/aarch64/a64tab.inc | 2 +- fpcsrc/compiler/aarch64/aasmcpu.pas | 1587 ++-- fpcsrc/compiler/aarch64/agcpugas.pas | 303 + fpcsrc/compiler/aarch64/aoptcpub.pas | 32 +- fpcsrc/compiler/aarch64/cgcpu.pas | 2275 ++++++ fpcsrc/compiler/aarch64/cpubase.pas | 238 +- fpcsrc/compiler/aarch64/cpuinfo.pas | 4 +- fpcsrc/compiler/aarch64/cpunode.pas | 40 + fpcsrc/compiler/aarch64/cpupara.pas | 977 ++- fpcsrc/compiler/aarch64/cpupi.pas | 68 + fpcsrc/compiler/aarch64/cputarg.pas | 70 + fpcsrc/compiler/aarch64/hlcgcpu.pas | 156 + fpcsrc/compiler/aarch64/ncpuadd.pas | 402 + fpcsrc/compiler/aarch64/ncpucnv.pas | 201 + fpcsrc/compiler/aarch64/ncpuinl.pas | 184 + fpcsrc/compiler/aarch64/ncpumat.pas | 196 + fpcsrc/compiler/aarch64/ncpumem.pas | 142 + fpcsrc/compiler/aarch64/ncpuset.pas | 175 + fpcsrc/compiler/aarch64/ra64con.inc | 5 + fpcsrc/compiler/aarch64/ra64dwa.inc | 319 +- fpcsrc/compiler/aarch64/ra64nor.inc | 2 +- fpcsrc/compiler/aarch64/ra64num.inc | 7 +- fpcsrc/compiler/aarch64/ra64rni.inc | 197 +- fpcsrc/compiler/aarch64/ra64sri.inc | 91 +- fpcsrc/compiler/aarch64/ra64sta.inc | 319 +- fpcsrc/compiler/aarch64/ra64std.inc | 7 +- fpcsrc/compiler/aarch64/ra64sup.inc | 5 + fpcsrc/compiler/aarch64/racpu.pas | 88 + fpcsrc/compiler/aarch64/racpugas.pas | 1053 +++ fpcsrc/compiler/aarch64/rgcpu.pas | 171 + fpcsrc/compiler/aasmtai.pas | 22 +- fpcsrc/compiler/aggas.pas | 9 +- fpcsrc/compiler/aoptobj.pas | 24 +- fpcsrc/compiler/arm/aasmcpu.pas | 4090 +++++++--- fpcsrc/compiler/arm/agarmgas.pas | 76 +- fpcsrc/compiler/arm/aoptcpu.pas | 2 +- fpcsrc/compiler/arm/armatt.inc | 258 +- fpcsrc/compiler/arm/armatts.inc | 22 + fpcsrc/compiler/arm/armins.dat | 1737 ++++- fpcsrc/compiler/arm/armnop.inc | 2 +- fpcsrc/compiler/arm/armop.inc | 258 +- fpcsrc/compiler/arm/armreg.dat | 11 +- fpcsrc/compiler/arm/armtab.inc | 6789 +++++++++++++++-- fpcsrc/compiler/arm/cgcpu.pas | 109 +- fpcsrc/compiler/arm/cpubase.pas | 55 +- fpcsrc/compiler/arm/cpuelf.pas | 36 +- fpcsrc/compiler/arm/cpuinfo.pas | 8 +- fpcsrc/compiler/arm/narmadd.pas | 51 +- fpcsrc/compiler/arm/narmcnv.pas | 11 +- fpcsrc/compiler/arm/narminl.pas | 26 +- fpcsrc/compiler/arm/narmmat.pas | 13 +- fpcsrc/compiler/arm/narmmem.pas | 7 +- fpcsrc/compiler/arm/raarmgas.pas | 289 +- fpcsrc/compiler/arm/rarmcon.inc | 7 + fpcsrc/compiler/arm/rarmdwa.inc | 7 + fpcsrc/compiler/arm/rarmnor.inc | 2 +- fpcsrc/compiler/arm/rarmnum.inc | 9 +- fpcsrc/compiler/arm/rarmrni.inc | 9 +- fpcsrc/compiler/arm/rarmsri.inc | 9 +- fpcsrc/compiler/arm/rarmsta.inc | 7 + fpcsrc/compiler/arm/rarmstd.inc | 11 +- fpcsrc/compiler/arm/rarmsup.inc | 7 + fpcsrc/compiler/assemble.pas | 16 +- fpcsrc/compiler/cgbase.pas | 13 + fpcsrc/compiler/cghlcpu.pas | 4 +- fpcsrc/compiler/cgobj.pas | 13 +- fpcsrc/compiler/cgutils.pas | 6 + fpcsrc/compiler/fpcdefs.inc | 1 + fpcsrc/compiler/hlcg2ll.pas | 6 +- fpcsrc/compiler/hlcgobj.pas | 28 +- fpcsrc/compiler/i386/cpuelf.pas | 1 + fpcsrc/compiler/i8086/n8086mem.pas | 9 +- fpcsrc/compiler/jvm/hlcgcpu.pas | 4 +- fpcsrc/compiler/m68k/n68kmem.pas | 5 +- fpcsrc/compiler/mips/cpuelf.pas | 1 + fpcsrc/compiler/msg/errore.msg | 8 + fpcsrc/compiler/msgidx.inc | 2 +- fpcsrc/compiler/ncal.pas | 1294 ++-- fpcsrc/compiler/ncgcnv.pas | 5 + fpcsrc/compiler/ncginl.pas | 12 +- fpcsrc/compiler/ncgld.pas | 14 +- fpcsrc/compiler/ncgmat.pas | 95 +- fpcsrc/compiler/ncgmem.pas | 72 +- fpcsrc/compiler/ncgutil.pas | 143 +- fpcsrc/compiler/ncnv.pas | 8 +- fpcsrc/compiler/ninl.pas | 4 + fpcsrc/compiler/nld.pas | 4 +- fpcsrc/compiler/nmem.pas | 22 +- fpcsrc/compiler/objcgutl.pas | 2 +- fpcsrc/compiler/objcutil.pas | 8 +- fpcsrc/compiler/ogbase.pas | 17 + fpcsrc/compiler/ogcoff.pas | 40 +- fpcsrc/compiler/ogelf.pas | 12 + fpcsrc/compiler/options.pas | 52 +- fpcsrc/compiler/pparautl.pas | 14 +- fpcsrc/compiler/ppu.pas | 6 +- fpcsrc/compiler/psub.pas | 6 + fpcsrc/compiler/psystem.pas | 5 +- fpcsrc/compiler/raatt.pas | 42 +- fpcsrc/compiler/rautils.pas | 14 +- fpcsrc/compiler/sparc/cpuelf.pas | 1 + fpcsrc/compiler/symdef.pas | 8 +- fpcsrc/compiler/systems.inc | 11 +- fpcsrc/compiler/systems.pas | 32 +- fpcsrc/compiler/systems/i_bsd.pas | 137 +- fpcsrc/compiler/systems/i_linux.pas | 72 + fpcsrc/compiler/systems/i_win.pas | 2 +- fpcsrc/compiler/systems/t_bsd.pas | 162 +- fpcsrc/compiler/systems/t_linux.pas | 240 + fpcsrc/compiler/tgobj.pas | 2 +- fpcsrc/compiler/utils/Makefile.fpc | 2 +- fpcsrc/compiler/utils/fpc.pp | 8 +- fpcsrc/compiler/utils/mka64ins.pp | 4 +- fpcsrc/compiler/utils/mkarmins.pp | 10 +- fpcsrc/compiler/utils/ppuutils/ppudump.pp | 14 +- fpcsrc/compiler/version.pas | 3 + fpcsrc/compiler/x86/agx86att.pas | 4 +- fpcsrc/compiler/x86/cgx86.pas | 39 +- fpcsrc/compiler/x86/nx86mem.pas | 5 +- fpcsrc/compiler/x86_64/cgcpu.pas | 2 +- fpcsrc/compiler/x86_64/cpuelf.pas | 1 + fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake | 2 +- fpcsrc/packages/fcl-res/src/elfconsts.pp | 4 +- .../packages/fcl-res/src/elfdefaulttarget.inc | 3 + fpcsrc/packages/fcl-res/src/elfreader.pp | 1 + fpcsrc/packages/fcl-res/src/elfsubwriter.inc | 3 +- fpcsrc/packages/fcl-res/src/elfwriter.pp | 3 +- fpcsrc/packages/fcl-res/src/machoconsts.pp | 8 + .../fcl-res/src/machodefaulttarget.inc | 3 + fpcsrc/packages/fcl-res/src/machoreader.pp | 3 +- .../packages/fcl-res/src/machosubwriter.inc | 88 +- fpcsrc/packages/fcl-res/src/machotypes.pp | 27 +- fpcsrc/packages/fcl-res/src/machowriter.pp | 73 +- fpcsrc/packages/fpmkunit/src/fpmkunit.pp | 83 +- .../packages/iosxlocale/Makefile.fpc.fpcmake | 2 +- fpcsrc/packages/iosxlocale/fpmake.pp | 1 + fpcsrc/packages/iosxlocale/src/iosxwstr.pp | 665 ++ .../packages/rtl-extra/src/linux/unixsock.inc | 2 +- fpcsrc/packages/rtl-extra/src/unix/ipc.pp | 2 +- fpcsrc/rtl/aarch64/aarch64.inc | 322 + fpcsrc/rtl/aarch64/int64p.inc | 15 + fpcsrc/rtl/aarch64/makefile.cpu | 7 + fpcsrc/rtl/aarch64/math.inc | 86 + fpcsrc/rtl/aarch64/mathu.inc | 157 + fpcsrc/rtl/aarch64/set.inc | 15 + fpcsrc/rtl/aarch64/setjump.inc | 59 + fpcsrc/rtl/aarch64/setjumph.inc | 45 + fpcsrc/rtl/aarch64/strings.inc | 17 + fpcsrc/rtl/aarch64/stringss.inc | 18 + fpcsrc/rtl/arm/arm.inc | 2 - fpcsrc/rtl/arm/thumb2.inc | 2 +- fpcsrc/rtl/bsd/ostypes.inc | 14 +- fpcsrc/rtl/darwin/aarch64/sig_cpu.inc | 47 + fpcsrc/rtl/darwin/aarch64/sighnd.inc | 61 + fpcsrc/rtl/darwin/extres_multiarch.inc | 34 +- fpcsrc/rtl/darwin/ptypes.inc | 4 +- fpcsrc/rtl/darwin/signal.inc | 4 + fpcsrc/rtl/inc/ctypes.pp | 4 + fpcsrc/rtl/inc/objc.pp | 2 +- fpcsrc/rtl/inc/objcnf.inc | 12 +- fpcsrc/rtl/inc/system.inc | 7 + fpcsrc/rtl/inc/systemh.inc | 36 +- fpcsrc/rtl/linux/aarch64/bsyscall.inc | 1 + fpcsrc/rtl/linux/aarch64/cprt0.as | 81 + fpcsrc/rtl/linux/aarch64/dllprt0.as | 72 + fpcsrc/rtl/linux/aarch64/gprt0.as | 10 + fpcsrc/rtl/linux/aarch64/prt0.as | 77 + fpcsrc/rtl/linux/aarch64/sighnd.inc | 44 + fpcsrc/rtl/linux/aarch64/sighndh.inc | 47 + fpcsrc/rtl/linux/aarch64/stat.inc | 72 + fpcsrc/rtl/linux/aarch64/syscall.inc | 127 + fpcsrc/rtl/linux/aarch64/syscallh.inc | 35 + fpcsrc/rtl/linux/aarch64/sysnr.inc | 1 + fpcsrc/rtl/linux/bunxsysc.inc | 81 +- fpcsrc/rtl/linux/linux.pp | 15 + fpcsrc/rtl/linux/oldlinux.pp | 30 + fpcsrc/rtl/linux/osdefs.inc | 4 + fpcsrc/rtl/linux/ossysc.inc | 60 +- fpcsrc/rtl/linux/ostypes.inc | 7 +- fpcsrc/rtl/linux/pmutext.inc | 58 + fpcsrc/rtl/linux/ptypes.inc | 41 +- fpcsrc/rtl/linux/sysnr-gen.inc | 277 + fpcsrc/rtl/linux/sysosh.inc | 16 +- fpcsrc/rtl/linux/termios.inc | 265 + fpcsrc/rtl/unix/cthreads.pp | 4 + fpcsrc/rtl/unix/cwstring.pp | 4 +- fpcsrc/utils/fpcm/fpcmmain.pp | 84 +- fpcsrc/utils/fpcres/fpcres.pas | 8 +- fpcsrc/utils/fpcres/target.pas | 58 +- 196 files changed, 24723 insertions(+), 5724 deletions(-) create mode 100644 fpcsrc/compiler/aarch64/agcpugas.pas create mode 100644 fpcsrc/compiler/aarch64/cgcpu.pas create mode 100644 fpcsrc/compiler/aarch64/cpunode.pas create mode 100644 fpcsrc/compiler/aarch64/cpupi.pas create mode 100644 fpcsrc/compiler/aarch64/cputarg.pas create mode 100644 fpcsrc/compiler/aarch64/hlcgcpu.pas create mode 100644 fpcsrc/compiler/aarch64/ncpuadd.pas create mode 100644 fpcsrc/compiler/aarch64/ncpucnv.pas create mode 100644 fpcsrc/compiler/aarch64/ncpuinl.pas create mode 100644 fpcsrc/compiler/aarch64/ncpumat.pas create mode 100644 fpcsrc/compiler/aarch64/ncpumem.pas create mode 100644 fpcsrc/compiler/aarch64/ncpuset.pas create mode 100644 fpcsrc/compiler/aarch64/racpu.pas create mode 100644 fpcsrc/compiler/aarch64/racpugas.pas create mode 100644 fpcsrc/compiler/aarch64/rgcpu.pas create mode 100644 fpcsrc/packages/iosxlocale/src/iosxwstr.pp create mode 100644 fpcsrc/rtl/aarch64/aarch64.inc create mode 100644 fpcsrc/rtl/aarch64/int64p.inc create mode 100644 fpcsrc/rtl/aarch64/makefile.cpu create mode 100644 fpcsrc/rtl/aarch64/math.inc create mode 100644 fpcsrc/rtl/aarch64/mathu.inc create mode 100644 fpcsrc/rtl/aarch64/set.inc create mode 100644 fpcsrc/rtl/aarch64/setjump.inc create mode 100644 fpcsrc/rtl/aarch64/setjumph.inc create mode 100644 fpcsrc/rtl/aarch64/strings.inc create mode 100644 fpcsrc/rtl/aarch64/stringss.inc create mode 100644 fpcsrc/rtl/darwin/aarch64/sig_cpu.inc create mode 100644 fpcsrc/rtl/darwin/aarch64/sighnd.inc create mode 100644 fpcsrc/rtl/linux/aarch64/bsyscall.inc create mode 100644 fpcsrc/rtl/linux/aarch64/cprt0.as create mode 100644 fpcsrc/rtl/linux/aarch64/dllprt0.as create mode 100644 fpcsrc/rtl/linux/aarch64/gprt0.as create mode 100644 fpcsrc/rtl/linux/aarch64/prt0.as create mode 100644 fpcsrc/rtl/linux/aarch64/sighnd.inc create mode 100644 fpcsrc/rtl/linux/aarch64/sighndh.inc create mode 100644 fpcsrc/rtl/linux/aarch64/stat.inc create mode 100644 fpcsrc/rtl/linux/aarch64/syscall.inc create mode 100644 fpcsrc/rtl/linux/aarch64/syscallh.inc create mode 100644 fpcsrc/rtl/linux/aarch64/sysnr.inc create mode 100644 fpcsrc/rtl/linux/pmutext.inc create mode 100644 fpcsrc/rtl/linux/sysnr-gen.inc diff --git a/fpcsrc/Makefile.fpc b/fpcsrc/Makefile.fpc index 1435e4da..6d464b21 100644 --- a/fpcsrc/Makefile.fpc +++ b/fpcsrc/Makefile.fpc @@ -78,6 +78,9 @@ endif ifeq ($(CPU_TARGET),avr) PPSUF=avr endif +ifeq ($(CPU_TARGET),aarch64) +PPSUF=a64 +endif # cross compilers uses full cpu_target, not just ppc-suffix # (except if the target cannot run a native compiler) diff --git a/fpcsrc/compiler/Makefile.fpc b/fpcsrc/compiler/Makefile.fpc index d617dcee..df2c5d7c 100644 --- a/fpcsrc/compiler/Makefile.fpc +++ b/fpcsrc/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 +CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 # All supported targets used for clean ALLTARGETS=$(CYCLETARGETS) @@ -80,6 +80,9 @@ endif ifdef I8086 PPC_TARGET=i8086 endif +ifdef AARCH64 +PPC_TARGET=aarch64 +endif # Default is to generate a compiler for the same # platform as CPU_TARGET (a native compiler) @@ -205,6 +208,9 @@ endif ifeq ($(CPC_TARGET),i8086) CPUSUF=8086 endif +ifeq ($(CPC_TARGET),aarch64) +CPUSUF=a64 +endif # Do not define the default -d$(CPU_TARGET) because that # will conflict with our -d$(CPC_TARGET) @@ -400,7 +406,7 @@ endif # CPU targets ##################################################################### -PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 alpha vis ia64 mips mipsel avr jvm i8086 +PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 alpha vis ia64 mips mipsel avr jvm i8086 aarch64 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS))) .PHONY: $(PPC_TARGETS) $(INSTALL_TARGETS) @@ -455,12 +461,12 @@ tempclean: -$(DEL) $(PPCROSSNAME) $(TEMPNAME) $(TEMPNAME1) $(TEMPNAME2) $(TEMPNAME3) $(MSG2INC) pp1.wpo pp2.wpo execlean : - -$(DEL) ppc386$(EXEEXT) ppc68k$(EXEEXT) ppcx64$(EXEEXT) ppcppc$(EXEEXT) ppcsparc$(EXEEXT) ppcppc64$(EXEEXT) ppcarm$(EXEEXT) ppcmips$(EXEEXT) ppcmipsel$(EXEEXT) ppcjvm$(EXEEXT) ppc8086$(EXEEXT) $(EXENAME) $(TEMPWPONAME1) $(TEMPWPONAME2) + -$(DEL) ppc386$(EXEEXT) ppc68k$(EXEEXT) ppcx64$(EXEEXT) ppcppc$(EXEEXT) ppcsparc$(EXEEXT) ppcppc64$(EXEEXT) ppcarm$(EXEEXT) ppcmips$(EXEEXT) ppcmipsel$(EXEEXT) ppcjvm$(EXEEXT) ppc8086$(EXEEXT) ppca64$(EXEEXT) $(EXENAME) $(TEMPWPONAME1) $(TEMPWPONAME2) $(addsuffix _clean,$(ALLTARGETS)): -$(DELTREE) $(addprefix $(subst _clean,,$@),/units) -$(DEL) $(addprefix $(subst _clean,,$@)/,*$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT)) - -$(DEL) $(addprefix $(subst _clean,,$@)/,ppc386$(EXEEXT) ppc68k$(EXEEXT) ppcx64$(EXEEXT) ppcppc$(EXEEXT) ppcsparc$(EXEEXT) ppcppc64$(EXEEXT) ppcarm$(EXEEXT) ppcmips$(EXEEXT) ppcmipsel$(EXEEXT) ppcjvm$(EXEEXT) ppc8086$(EXEEXT) $(EXENAME)) + -$(DEL) $(addprefix $(subst _clean,,$@)/,ppc386$(EXEEXT) ppc68k$(EXEEXT) ppcx64$(EXEEXT) ppcppc$(EXEEXT) ppcsparc$(EXEEXT) ppcppc64$(EXEEXT) ppcarm$(EXEEXT) ppcmips$(EXEEXT) ppcmipsel$(EXEEXT) ppcjvm$(EXEEXT) ppc8086$(EXEEXT) ppca64$(EXEEXT) $(EXENAME)) cycleclean: cleanall $(addsuffix _clean,$(CPC_TARGET)) -$(DEL) $(EXENAME) diff --git a/fpcsrc/compiler/aarch64/a64att.inc b/fpcsrc/compiler/aarch64/a64att.inc index ad0b8050..35971906 100644 --- a/fpcsrc/compiler/aarch64/a64att.inc +++ b/fpcsrc/compiler/aarch64/a64att.inc @@ -1,15 +1,37 @@ -{ don't edit, this file is generated from armins.dat } +{ don't edit, this file is generated from a64ins.dat } ( -'nop', +'none', 'b', -'cb', -'tb', +'cbz', +'cbnz', +'tbz', +'tbnz', 'bl', 'blr', 'br', 'ret', +'brk', +'hlt', +'hvc', +'smc', +'svc', +'eret', +'dcps1', +'dcps2', +'dcps3', +'drps', +'dc', +'at', +'tlbi', +'hint', +'clrex', +'dsb', +'dmb', +'isb', 'ldr', 'str', +'ldur', +'stur', 'ldp', 'stp', 'ldnp', @@ -17,40 +39,66 @@ 'ldtr', 'sttr', 'ldxr', +'ldxp', 'stxr', +'stxp', 'ldar', 'stlr', 'ldaxr', 'stlxr', +'stlxp', +'ld1', +'ld2', +'ld3', +'ld4', +'st1', +'st2', +'st3', +'st4', +'ld1r', +'ld2r', +'ld3r', +'ld4r', 'prfm', +'prfum', 'add', -'adc', 'sub', -'sbc', 'cmp', 'cmn', -'mov', 'and', -'bic', 'eor', -'eon', 'orr', 'orn', 'tst', -'mvn', +'movz', +'movn', 'movk', +'mrs', +'msr', 'adrp', 'adr', 'bfm', 'sbfm', 'ubfm', 'extr', -'sxt', -'uxt', +'adc', +'sbc', +'bic', +'eon', 'asrv', -'llslv', +'lslv', 'lsrv', 'rorv', +'madd', +'msub', +'smaddl', +'smsubl', +'smulh', +'umaddl', +'umsubl', +'umulh', +'sdiv', +'udiv', 'cls', 'clz', 'rbit', @@ -63,33 +111,39 @@ 'csneg', 'ccmn', 'ccmp', -'madd', -'msub', -'smaddl', -'smsubl', -'smulh', -'umaddl', -'umsubl', -'umulh', -'sdiv', -'udiv', -'neg', +'nop', +'yield', +'wfe', +'wfi', +'sev', +'sevl', +'mov', +'bfi', +'bfxil', +'sbfiz', +'sbfx', +'ubfiz', +'ubfx', 'asr', 'lsl', 'lsr', 'ror', -'cset', -'csetm', -'cinc', -'cinv', -'cneg', +'sxt', +'uxt', +'neg', 'ngc', +'mvn', 'mneg', 'mul', 'smnegl', 'smull', 'umnegl', 'umull', +'cset', +'csetm', +'cinc', +'cinv', +'cneg', 'fmov', 'fcvt', 'fcvtas', @@ -104,13 +158,13 @@ 'fcvtzu', 'scvtf', 'ucvtf', -'fprinta', -'fprinti', -'fprintm', -'fprintn', -'fprintp', -'fprintx', -'fprintz', +'frinta', +'frinti', +'frintm', +'frintn', +'frintp', +'frintx', +'frintz', 'fabs', 'fneg', 'fsqrt', @@ -130,5 +184,8 @@ 'fcmpe', 'fccmp', 'fcmmpe', -'fcsel' +'fcsel', +'umov', +'ins', +'movi' ); diff --git a/fpcsrc/compiler/aarch64/a64atts.inc b/fpcsrc/compiler/aarch64/a64atts.inc index 6b59b55a..560b3cbb 100644 --- a/fpcsrc/compiler/aarch64/a64atts.inc +++ b/fpcsrc/compiler/aarch64/a64atts.inc @@ -1,4 +1,4 @@ -{ don't edit, this file is generated from armins.dat } +{ don't edit, this file is generated from a64ins.dat } ( attsufNONE, attsufNONE, @@ -130,5 +130,62 @@ attsufNONE, attsufNONE, attsufNONE, attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, attsufNONE ); diff --git a/fpcsrc/compiler/aarch64/a64ins.dat b/fpcsrc/compiler/aarch64/a64ins.dat index 34fae63c..8032befc 100644 --- a/fpcsrc/compiler/aarch64/a64ins.dat +++ b/fpcsrc/compiler/aarch64/a64ins.dat @@ -1,10 +1,15 @@ -[NOP] +; invalid +[NONE] [B] -[CB] +[CBZ] + +[CBNZ] -[TB] +[TBZ] + +[TBNZ] [BL] @@ -14,10 +19,50 @@ [RET] +[BRK] + +[HLT] + +[HVC] + +[SMC] + +[SVC] + +[ERET] + +[DCPS1] + +[DCPS2] + +[DCPS3] + +[DRPS] + +[DC] + +[AT] + +[TLBI] + +[HINT] + +[CLREX] + +[DSB] + +[DMB] + +[ISB] + [LDR] [STR] +[LDUR] + +[STUR] + [LDP] [STP] @@ -32,8 +77,12 @@ [LDXR] +[LDXP] + [STXR] +[STXP] + [LDAR] [STLR] @@ -42,40 +91,64 @@ [STLXR] +[STLXP] + +[LD1] + +[LD2] + +[LD3] + +[LD4] + +[ST1] + +[ST2] + +[ST3] + +[ST4] + +[LD1R] + +[LD2R] + +[LD3R] + +[LD4R] + [PRFM] -[ADD] +[PRFUM] -[ADC] +[ADD] [SUB] -[SBC] - [CMP] [CMN] -[MOV] - [AND] -[BIC] - [EOR] -[EON] - [ORR] [ORN] [TST] -[MVN] +[MOVZ] + +[MOVN] [MOVK] +[MRS] + +[MSR] + [ADRP] [ADR] @@ -88,18 +161,42 @@ [EXTR] -[SXT] +[ADC] -[UXT] +[SBC] + +[BIC] + +[EON] [ASRV] -[LLSLV] +[LSLV] [LSRV] [RORV] +[MADD] + +[MSUB] + +[SMADDL] + +[SMSUBL] + +[SMULH] + +[UMADDL] + +[UMSUBL] + +[UMULH] + +[SDIV] + +[UDIV] + [CLS] [CLZ] @@ -124,29 +221,33 @@ [CCMP] -[MADD] +; Aliases +; they are not generated by the compiler, they are only used for inline assembler +[NOP] -[MSUB] +[YIELD] -[SMADDL] +[WFE] -[SMSUBL] +[WFI] -[SMULH] +[SEV] -[UMADDL] +[SEVL] -[UMSUBL] +[MOV] -[UMULH] +[BFI] -[SDIV] +[BFXIL] -[UDIV] +[SBFIZ] -; Aliases -; they are not generated by the compiler, they are only used for inline assembler -[NEG] +[SBFX] + +[UBFIZ] + +[UBFX] [ASR] @@ -156,18 +257,16 @@ [ROR] -[CSET] - -[CSETM] - -[CINC] +[SXT] -[CINV] +[UXT] -[CNEG] +[NEG] [NGC] +[MVN] + [MNEG] [MUL] @@ -180,6 +279,16 @@ [UMULL] +[CSET] + +[CSETM] + +[CINC] + +[CINV] + +[CNEG] + [FMOV] [FCVT] @@ -208,19 +317,19 @@ [UCVTF] -[FPRINTA] +[FRINTA] -[FPRINTI] +[FRINTI] -[FPRINTM] +[FRINTM] -[FPRINTN] +[FRINTN] -[FPRINTP] +[FRINTP] -[FPRINTX] +[FRINTX] -[FPRINTZ] +[FRINTZ] [FABS] @@ -262,3 +371,8 @@ [FCSEL] +[UMOV] + +[INS] + +[MOVI] diff --git a/fpcsrc/compiler/aarch64/a64op.inc b/fpcsrc/compiler/aarch64/a64op.inc index 05faf81a..244c232d 100644 --- a/fpcsrc/compiler/aarch64/a64op.inc +++ b/fpcsrc/compiler/aarch64/a64op.inc @@ -1,15 +1,37 @@ -{ don't edit, this file is generated from armins.dat } +{ don't edit, this file is generated from a64ins.dat } ( -A_NOP, +A_NONE, A_B, -A_CB, -A_TB, +A_CBZ, +A_CBNZ, +A_TBZ, +A_TBNZ, A_BL, A_BLR, A_BR, A_RET, +A_BRK, +A_HLT, +A_HVC, +A_SMC, +A_SVC, +A_ERET, +A_DCPS1, +A_DCPS2, +A_DCPS3, +A_DRPS, +A_DC, +A_AT, +A_TLBI, +A_HINT, +A_CLREX, +A_DSB, +A_DMB, +A_ISB, A_LDR, A_STR, +A_LDUR, +A_STUR, A_LDP, A_STP, A_LDNP, @@ -17,40 +39,66 @@ A_STNP, A_LDTR, A_STTR, A_LDXR, +A_LDXP, A_STXR, +A_STXP, A_LDAR, A_STLR, A_LDAXR, A_STLXR, +A_STLXP, +A_LD1, +A_LD2, +A_LD3, +A_LD4, +A_ST1, +A_ST2, +A_ST3, +A_ST4, +A_LD1R, +A_LD2R, +A_LD3R, +A_LD4R, A_PRFM, +A_PRFUM, A_ADD, -A_ADC, A_SUB, -A_SBC, A_CMP, A_CMN, -A_MOV, A_AND, -A_BIC, A_EOR, -A_EON, A_ORR, A_ORN, A_TST, -A_MVN, +A_MOVZ, +A_MOVN, A_MOVK, +A_MRS, +A_MSR, A_ADRP, A_ADR, A_BFM, A_SBFM, A_UBFM, A_EXTR, -A_SXT, -A_UXT, +A_ADC, +A_SBC, +A_BIC, +A_EON, A_ASRV, -A_LLSLV, +A_LSLV, A_LSRV, A_RORV, +A_MADD, +A_MSUB, +A_SMADDL, +A_SMSUBL, +A_SMULH, +A_UMADDL, +A_UMSUBL, +A_UMULH, +A_SDIV, +A_UDIV, A_CLS, A_CLZ, A_RBIT, @@ -63,33 +111,39 @@ A_CSINV, A_CSNEG, A_CCMN, A_CCMP, -A_MADD, -A_MSUB, -A_SMADDL, -A_SMSUBL, -A_SMULH, -A_UMADDL, -A_UMSUBL, -A_UMULH, -A_SDIV, -A_UDIV, -A_NEG, +A_NOP, +A_YIELD, +A_WFE, +A_WFI, +A_SEV, +A_SEVL, +A_MOV, +A_BFI, +A_BFXIL, +A_SBFIZ, +A_SBFX, +A_UBFIZ, +A_UBFX, A_ASR, A_LSL, A_LSR, A_ROR, -A_CSET, -A_CSETM, -A_CINC, -A_CINV, -A_CNEG, +A_SXT, +A_UXT, +A_NEG, A_NGC, +A_MVN, A_MNEG, A_MUL, A_SMNEGL, A_SMULL, A_UMNEGL, A_UMULL, +A_CSET, +A_CSETM, +A_CINC, +A_CINV, +A_CNEG, A_FMOV, A_FCVT, A_FCVTAS, @@ -104,13 +158,13 @@ A_FCVTZS, A_FCVTZU, A_SCVTF, A_UCVTF, -A_FPRINTA, -A_FPRINTI, -A_FPRINTM, -A_FPRINTN, -A_FPRINTP, -A_FPRINTX, -A_FPRINTZ, +A_FRINTA, +A_FRINTI, +A_FRINTM, +A_FRINTN, +A_FRINTP, +A_FRINTX, +A_FRINTZ, A_FABS, A_FNEG, A_FSQRT, @@ -130,5 +184,8 @@ A_FCMP, A_FCMPE, A_FCCMP, A_FCMMPE, -A_FCSEL +A_FCSEL, +A_UMOV, +A_INS, +A_MOVI ); diff --git a/fpcsrc/compiler/aarch64/a64reg.dat b/fpcsrc/compiler/aarch64/a64reg.dat index f1da4aed..0ede14cb 100644 --- a/fpcsrc/compiler/aarch64/a64reg.dat +++ b/fpcsrc/compiler/aarch64/a64reg.dat @@ -70,169 +70,176 @@ W30,$01,$04,$1E,w30,30,30 X30,$01,$05,$1E,x30,30,30 WZR,$01,$04,$1F,wzr,31,31 XZR,$01,$05,$1F,xzr,31,31 +; sp and zr share the same register number, but we still have to be able to +; differentiate them because some instructions can be encoded with both -> +; use a different superregister after all +WSP,$01,$04,$20,wsp,31,31 +SP,$01,$05,$20,sp,31,31 ; vfp registers -B0,$04,$01,$00,b0,0,0 -H0,$04,$03,$00,h0,0,0 -S0,$04,$09,$00,s0,0,0 -D0,$04,$0a,$00,d0,0,0 -Q0,$04,$05,$00,q0,0,0 -B1,$04,$01,$01,b1,1,1 -H1,$04,$03,$01,h1,1,1 -S1,$04,$09,$01,s1,1,1 -D1,$04,$0a,$01,d1,1,1 -Q1,$04,$05,$01,q1,1,1 -B2,$04,$01,$02,b2,2,2 -H2,$04,$03,$02,h2,2,2 -S2,$04,$09,$02,s2,2,2 -D2,$04,$0a,$02,d2,2,2 -Q2,$04,$05,$02,q2,2,2 -B3,$04,$01,$03,b3,3,3 -H3,$04,$03,$03,h3,3,3 -S3,$04,$09,$03,s3,3,3 -D3,$04,$0a,$03,d3,3,3 -Q3,$04,$05,$03,q3,3,3 -B4,$04,$01,$04,b4,4,4 -H4,$04,$03,$04,h4,4,4 -S4,$04,$09,$04,s4,4,4 -D4,$04,$0a,$04,d4,4,4 -Q4,$04,$05,$04,q4,4,4 -B5,$04,$01,$05,b5,5,5 -H5,$04,$03,$05,h5,5,5 -S5,$04,$09,$05,s5,5,5 -D5,$04,$0a,$05,d5,5,5 -Q5,$04,$05,$05,q5,5,5 -B6,$04,$01,$06,b6,6,6 -H6,$04,$03,$06,h6,6,6 -S6,$04,$09,$06,s6,6,6 -D6,$04,$0a,$06,d6,6,6 -Q6,$04,$05,$06,q6,6,6 -B7,$04,$01,$07,b7,7,7 -H7,$04,$03,$07,h7,7,7 -S7,$04,$09,$07,s7,7,7 -D7,$04,$0a,$07,d7,7,7 -Q7,$04,$05,$07,q7,7,7 -B8,$04,$01,$08,b8,8,8 -H8,$04,$03,$08,h8,8,8 -S8,$04,$09,$08,s8,8,8 -D8,$04,$0a,$08,d8,8,8 -Q8,$04,$05,$08,q8,8,8 -B9,$04,$01,$09,b9,9,9 -H9,$04,$03,$09,h9,9,9 -S9,$04,$09,$09,s9,9,9 -D9,$04,$0a,$09,d9,9,9 -Q9,$04,$05,$09,q9,9,9 -B10,$04,$01,$0A,b10,10,10 -H10,$04,$03,$0A,h10,10,10 -S10,$04,$09,$0A,s10,10,10 -D10,$04,$0a,$0A,d10,10,10 -Q10,$04,$05,$0A,q10,10,10 -B11,$04,$01,$0B,b11,11,11 -H11,$04,$03,$0B,h11,11,11 -S11,$04,$09,$0B,s11,11,11 -D11,$04,$0a,$0B,d11,11,11 -Q11,$04,$05,$0B,q11,11,11 -B12,$04,$01,$0C,b12,12,12 -H12,$04,$03,$0C,h12,12,12 -S12,$04,$09,$0C,s12,12,12 -D12,$04,$0a,$0C,d12,12,12 -Q12,$04,$05,$0C,q12,12,12 -B13,$04,$01,$0D,b13,13,13 -H13,$04,$03,$0D,h13,13,13 -S13,$04,$09,$0D,s13,13,13 -D13,$04,$0a,$0D,d13,13,13 -Q13,$04,$05,$0D,q13,13,13 -B14,$04,$01,$0E,b14,14,14 -H14,$04,$03,$0E,h14,14,14 -S14,$04,$09,$0E,s14,14,14 -D14,$04,$0a,$0E,d14,14,14 -Q14,$04,$05,$0E,q14,14,14 -B15,$04,$01,$0F,b15,15,15 -H15,$04,$03,$0F,h15,15,15 -S15,$04,$09,$0F,s15,15,15 -D15,$04,$0a,$0F,d15,15,15 -Q15,$04,$05,$0F,q15,15,15 -B16,$04,$01,$10,b16,16,16 -H16,$04,$03,$10,h16,16,16 -S16,$04,$09,$10,s16,16,16 -D16,$04,$0a,$10,d16,16,16 -Q16,$04,$05,$10,q16,16,16 -B17,$04,$01,$11,b17,17,17 -H17,$04,$03,$11,h17,17,17 -S17,$04,$09,$11,s17,17,17 -D17,$04,$0a,$11,d17,17,17 -Q17,$04,$05,$11,q17,17,17 -B18,$04,$01,$12,b18,18,18 -H18,$04,$03,$12,h18,18,18 -S18,$04,$09,$12,s18,18,18 -D18,$04,$0a,$12,d18,18,18 -Q18,$04,$05,$12,q18,18,18 -B19,$04,$01,$13,b19,19,19 -H19,$04,$03,$13,h19,19,19 -S19,$04,$09,$13,s19,19,19 -D19,$04,$0a,$13,d19,19,19 -Q19,$04,$05,$13,q19,19,19 -B20,$04,$01,$14,b20,20,20 -H20,$04,$03,$14,h20,20,20 -S20,$04,$09,$14,s20,20,20 -D20,$04,$0a,$14,d20,20,20 -Q20,$04,$05,$14,q20,20,20 -B21,$04,$01,$15,b21,21,21 -H21,$04,$03,$15,h21,21,21 -S21,$04,$09,$15,s21,21,21 -D21,$04,$0a,$15,d21,21,21 -Q21,$04,$05,$15,q21,21,21 -B22,$04,$01,$16,b22,22,22 -H22,$04,$03,$16,h22,22,22 -S22,$04,$09,$16,s22,22,22 -D22,$04,$0a,$16,d22,22,22 -Q22,$04,$05,$16,q22,22,22 -B23,$04,$01,$17,b23,23,23 -H23,$04,$03,$17,h23,23,23 -S23,$04,$09,$17,s23,23,23 -D23,$04,$0a,$17,d23,23,23 -Q23,$04,$05,$17,q23,23,23 -B24,$04,$01,$18,b24,24,24 -H24,$04,$03,$18,h24,24,24 -S24,$04,$09,$18,s24,24,24 -D24,$04,$0a,$18,d24,24,24 -Q24,$04,$05,$18,q24,24,24 -B25,$04,$01,$19,b25,25,25 -H25,$04,$03,$19,h25,25,25 -S25,$04,$09,$19,s25,25,25 -D25,$04,$0a,$19,d25,25,25 -Q25,$04,$05,$19,q25,25,25 -B26,$04,$01,$1A,b26,26,26 -H26,$04,$03,$1A,h26,26,26 -S26,$04,$09,$1A,s26,26,26 -D26,$04,$0a,$1A,d26,26,26 -Q26,$04,$05,$1A,q26,26,26 -B27,$04,$01,$1B,b27,27,27 -H27,$04,$03,$1B,h27,27,27 -S27,$04,$09,$1B,s27,27,27 -D27,$04,$0a,$1B,d27,27,27 -Q27,$04,$05,$1B,q27,27,27 -B28,$04,$01,$1C,b28,28,28 -H28,$04,$03,$1C,h28,28,28 -S28,$04,$09,$1C,s28,28,28 -D28,$04,$0a,$1C,d28,28,28 -Q28,$04,$05,$1C,q28,28,28 -B29,$04,$01,$1D,b29,29,29 -H29,$04,$03,$1D,h29,29,29 -S29,$04,$09,$1D,s29,29,29 -D29,$04,$0a,$1D,d29,29,29 -Q29,$04,$05,$1D,q29,29,29 -B30,$04,$01,$1E,b30,30,30 -H30,$04,$03,$1E,h30,30,30 -S30,$04,$09,$1E,s30,30,30 -D30,$04,$0a,$1E,d30,30,30 -Q30,$04,$05,$1E,q30,30,30 -B31,$04,$01,$1F,b31,31,31 -H31,$04,$03,$1F,h31,31,31 -S31,$04,$09,$1F,s31,31,31 -D31,$04,$0a,$1F,d31,31,31 -Q31,$04,$05,$1F,q31,31,31 +B0,$04,$01,$00,b0,64,64 +H0,$04,$03,$00,h0,64,64 +S0,$04,$09,$00,s0,64,64 +D0,$04,$0a,$00,d0,64,64 +Q0,$04,$05,$00,q0,64,64 +B1,$04,$01,$01,b1,65,65 +H1,$04,$03,$01,h1,65,65 +S1,$04,$09,$01,s1,65,65 +D1,$04,$0a,$01,d1,65,65 +Q1,$04,$05,$01,q1,65,65 +B2,$04,$01,$02,b2,66,66 +H2,$04,$03,$02,h2,66,66 +S2,$04,$09,$02,s2,66,66 +D2,$04,$0a,$02,d2,66,66 +Q2,$04,$05,$02,q2,66,66 +B3,$04,$01,$03,b3,67,67 +H3,$04,$03,$03,h3,67,67 +S3,$04,$09,$03,s3,67,67 +D3,$04,$0a,$03,d3,67,67 +Q3,$04,$05,$03,q3,67,67 +B4,$04,$01,$04,b4,68,68 +H4,$04,$03,$04,h4,68,68 +S4,$04,$09,$04,s4,68,68 +D4,$04,$0a,$04,d4,68,68 +Q4,$04,$05,$04,q4,68,68 +B5,$04,$01,$05,b5,69,69 +H5,$04,$03,$05,h5,69,69 +S5,$04,$09,$05,s5,69,69 +D5,$04,$0a,$05,d5,69,69 +Q5,$04,$05,$05,q5,69,69 +B6,$04,$01,$06,b6,70,70 +H6,$04,$03,$06,h6,70,70 +S6,$04,$09,$06,s6,70,70 +D6,$04,$0a,$06,d6,70,70 +Q6,$04,$05,$06,q6,70,70 +B7,$04,$01,$07,b7,71,71 +H7,$04,$03,$07,h7,71,71 +S7,$04,$09,$07,s7,71,71 +D7,$04,$0a,$07,d7,71,71 +Q7,$04,$05,$07,q7,71,71 +B8,$04,$01,$08,b8,72,72 +H8,$04,$03,$08,h8,72,72 +S8,$04,$09,$08,s8,72,72 +D8,$04,$0a,$08,d8,72,72 +Q8,$04,$05,$08,q8,72,72 +B9,$04,$01,$09,b9,73,73 +H9,$04,$03,$09,h9,73,73 +S9,$04,$09,$09,s9,73,73 +D9,$04,$0a,$09,d9,73,73 +Q9,$04,$05,$09,q9,73,73 +B10,$04,$01,$0A,b10,74,74 +H10,$04,$03,$0A,h10,74,74 +S10,$04,$09,$0A,s10,74,74 +D10,$04,$0a,$0A,d10,74,74 +Q10,$04,$05,$0A,q10,74,74 +B11,$04,$01,$0B,b11,75,75 +H11,$04,$03,$0B,h11,75,75 +S11,$04,$09,$0B,s11,75,75 +D11,$04,$0a,$0B,d11,75,75 +Q11,$04,$05,$0B,q11,75,75 +B12,$04,$01,$0C,b12,76,76 +H12,$04,$03,$0C,h12,76,76 +S12,$04,$09,$0C,s12,76,76 +D12,$04,$0a,$0C,d12,76,76 +Q12,$04,$05,$0C,q12,76,76 +B13,$04,$01,$0D,b13,77,77 +H13,$04,$03,$0D,h13,77,77 +S13,$04,$09,$0D,s13,77,77 +D13,$04,$0a,$0D,d13,77,77 +Q13,$04,$05,$0D,q13,77,77 +B14,$04,$01,$0E,b14,78,78 +H14,$04,$03,$0E,h14,78,78 +S14,$04,$09,$0E,s14,78,78 +D14,$04,$0a,$0E,d14,78,78 +Q14,$04,$05,$0E,q14,78,78 +B15,$04,$01,$0F,b15,79,79 +H15,$04,$03,$0F,h15,79,79 +S15,$04,$09,$0F,s15,79,79 +D15,$04,$0a,$0F,d15,79,79 +Q15,$04,$05,$0F,q15,79,79 +B16,$04,$01,$10,b16,80,80 +H16,$04,$03,$10,h16,80,80 +S16,$04,$09,$10,s16,80,80 +D16,$04,$0a,$10,d16,80,80 +Q16,$04,$05,$10,q16,80,80 +B17,$04,$01,$11,b17,81,81 +H17,$04,$03,$11,h17,81,81 +S17,$04,$09,$11,s17,81,81 +D17,$04,$0a,$11,d17,81,81 +Q17,$04,$05,$11,q17,81,81 +B18,$04,$01,$12,b18,82,82 +H18,$04,$03,$12,h18,82,82 +S18,$04,$09,$12,s18,82,82 +D18,$04,$0a,$12,d18,82,82 +Q18,$04,$05,$12,q18,82,82 +B19,$04,$01,$13,b19,83,83 +H19,$04,$03,$13,h19,83,83 +S19,$04,$09,$13,s19,83,83 +D19,$04,$0a,$13,d19,83,83 +Q19,$04,$05,$13,q19,83,83 +B20,$04,$01,$14,b20,84,84 +H20,$04,$03,$14,h20,84,84 +S20,$04,$09,$14,s20,84,84 +D20,$04,$0a,$14,d20,84,84 +Q20,$04,$05,$14,q20,84,84 +B21,$04,$01,$15,b21,85,85 +H21,$04,$03,$15,h21,85,85 +S21,$04,$09,$15,s21,85,85 +D21,$04,$0a,$15,d21,85,85 +Q21,$04,$05,$15,q21,85,85 +B22,$04,$01,$16,b22,86,86 +H22,$04,$03,$16,h22,86,86 +S22,$04,$09,$16,s22,86,86 +D22,$04,$0a,$16,d22,86,86 +Q22,$04,$05,$16,q22,86,86 +B23,$04,$01,$17,b23,87,87 +H23,$04,$03,$17,h23,87,87 +S23,$04,$09,$17,s23,87,87 +D23,$04,$0a,$17,d23,87,87 +Q23,$04,$05,$17,q23,87,87 +B24,$04,$01,$18,b24,88,88 +H24,$04,$03,$18,h24,88,88 +S24,$04,$09,$18,s24,88,88 +D24,$04,$0a,$18,d24,88,88 +Q24,$04,$05,$18,q24,88,88 +B25,$04,$01,$19,b25,89,89 +H25,$04,$03,$19,h25,89,89 +S25,$04,$09,$19,s25,89,89 +D25,$04,$0a,$19,d25,89,89 +Q25,$04,$05,$19,q25,89,89 +B26,$04,$01,$1A,b26,90,90 +H26,$04,$03,$1A,h26,90,90 +S26,$04,$09,$1A,s26,90,90 +D26,$04,$0a,$1A,d26,90,90 +Q26,$04,$05,$1A,q26,90,90 +B27,$04,$01,$1B,b27,91,91 +H27,$04,$03,$1B,h27,91,91 +S27,$04,$09,$1B,s27,91,91 +D27,$04,$0a,$1B,d27,91,91 +Q27,$04,$05,$1B,q27,91,91 +B28,$04,$01,$1C,b28,92,92 +H28,$04,$03,$1C,h28,92,92 +S28,$04,$09,$1C,s28,92,92 +D28,$04,$0a,$1C,d28,92,92 +Q28,$04,$05,$1C,q28,92,92 +B29,$04,$01,$1D,b29,93,93 +H29,$04,$03,$1D,h29,93,93 +S29,$04,$09,$1D,s29,93,93 +D29,$04,$0a,$1D,d29,93,93 +Q29,$04,$05,$1D,q29,93,93 +B30,$04,$01,$1E,b30,94,94 +H30,$04,$03,$1E,h30,94,94 +S30,$04,$09,$1E,s30,94,94 +D30,$04,$0a,$1E,d30,94,94 +Q30,$04,$05,$1E,q30,94,94 +B31,$04,$01,$1F,b31,95,95 +H31,$04,$03,$1F,h31,95,95 +S31,$04,$09,$1F,s31,95,95 +D31,$04,$0a,$1F,d31,95,95 +Q31,$04,$05,$1F,q31,95,95 NZCV,$05,$00,$00,nzcv,0,0 - +FPCR,$05,$00,$01,fpcr,0,0 +FPSR,$05,$00,$02,fpsr,0,0 +TPIDR_EL0,$05,$00,$03,tpidr_el0,0,0 diff --git a/fpcsrc/compiler/aarch64/a64tab.inc b/fpcsrc/compiler/aarch64/a64tab.inc index 437c9126..bcf4b0dd 100644 --- a/fpcsrc/compiler/aarch64/a64tab.inc +++ b/fpcsrc/compiler/aarch64/a64tab.inc @@ -1,4 +1,4 @@ -{ don't edit, this file is generated from armins.dat } +{ don't edit, this file is generated from a64ins.dat } ( ); diff --git a/fpcsrc/compiler/aarch64/aasmcpu.pas b/fpcsrc/compiler/aarch64/aasmcpu.pas index 8624744d..f9888517 100644 --- a/fpcsrc/compiler/aarch64/aasmcpu.pas +++ b/fpcsrc/compiler/aarch64/aasmcpu.pas @@ -1,7 +1,7 @@ { Copyright (c) 2003-2012 by Florian Klaempfl and others - Contains the assembler object for ARM64 + Contains the assembler object for Aarch64 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 @@ -149,9 +149,6 @@ uses pinsentry=^tinsentry; -{ const - InsTab : array[0..instabentries-1] of TInsEntry={$i a64tab.inc} } - var InsTabCache : PInsTabCache; @@ -159,6 +156,7 @@ uses taicpu = class(tai_cpu_abstract_sym) oppostfix : TOpPostfix; procedure loadshifterop(opidx:longint;const so:tshifterop); + procedure loadconditioncode(opidx: longint; const c: tasmcond); constructor op_none(op : tasmop); constructor op_reg(op : tasmop;_op1 : tregister); @@ -167,15 +165,21 @@ uses constructor op_reg_reg(op : tasmop;_op1,_op2 : tregister); constructor op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); + constructor op_reg_cond(op: tasmop; _op1: tregister; _op2: tasmcond); constructor op_reg_const(op:tasmop; _op1: tregister; _op2: aint); + constructor op_reg_const_shifterop(op : tasmop;_op1: tregister; _op2: aint;_op3 : tshifterop); constructor op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); constructor op_reg_reg_reg_reg(op : tasmop;_op1,_op2,_op3,_op4 : tregister); constructor op_reg_reg_const(op : tasmop;_op1,_op2 : tregister; _op3: aint); + constructor op_reg_reg_const_const(op : tasmop;_op1,_op2 : tregister; _op3, _op4: aint); + constructor op_reg_reg_const_shifterop(op : tasmop;_op1,_op2 : tregister; _op3: aint; const _op4 : tshifterop); constructor op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); constructor op_reg_reg_ref(op : tasmop;_op1,_op2 : tregister; const _op3: treference); constructor op_reg_reg_shifterop(op : tasmop;_op1,_op2 : tregister;_op3 : tshifterop); - constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); + constructor op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister; const _op4 : tshifterop); + constructor op_reg_reg_reg_cond(op : tasmop;_op1,_op2,_op3 : tregister; const _op4: tasmcond); + { this is for Jmp instructions } constructor op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); @@ -188,6 +192,7 @@ uses function is_same_reg_move(regtype: Tregistertype):boolean; override; function spilling_get_operation_type(opnr: longint): topertype;override; + function spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype;override; { assembler } public @@ -203,28 +208,29 @@ uses procedure ppuwriteoper(ppufile:tcompilerppufile;const o:toper);override; procedure ppubuildderefimploper(var o:toper);override; procedure ppuderefoper(var o:toper);override; - private - { next fields are filled in pass1, so pass2 is faster } - inssize : shortint; - insoffset : longint; - LastInsOffset : longint; { need to be public to be reset } - insentry : PInsEntry; - function InsEnd:longint; - procedure create_ot(objdata:TObjData); - function Matches(p:PInsEntry):longint; - function calcsize(p:PInsEntry):shortint; - procedure gencode(objdata:TObjData); - function NeedAddrPrefix(opidx:byte):boolean; - procedure Swapoperands; - function FindInsentry(objdata:TObjData):boolean; end; tai_align = class(tai_align_abstract) { nothing to add } end; - function spilling_create_load(const ref:treference;r:tregister):Taicpu; - function spilling_create_store(r:tregister; const ref:treference):Taicpu; + type + tsimplereftype = + { valid reference } + (sr_simple, + { invalid reference, should not be generated by the code generator (but + can be encountered via inline assembly, where it must be rejected) } + sr_internal_illegal, + { invalid reference, may be generated by the code generator and then + must be simplified (also rejected in inline assembly) } + sr_complex); + + function simple_ref_type(op: tasmop; size:tcgsize; oppostfix: toppostfix; const ref: treference): tsimplereftype; + function can_be_shifter_operand(opc: tasmop; opnr: longint): boolean; + function valid_shifter_operand(opc: tasmop; useszr, usessp, is64bit: boolean; sm: tshiftmode; shiftimm: longint): boolean; + + function spilling_create_load(const ref: treference; r: tregister): taicpu; + function spilling_create_store(r: tregister; const ref: treference): taicpu; function setoppostfix(i : taicpu;pf : toppostfix) : taicpu; function setcondition(i : taicpu;c : tasmcond) : taicpu; @@ -261,6 +267,21 @@ implementation end; + procedure taicpu.loadconditioncode(opidx: longint; const c: tasmcond); + begin + allocate_oper(opidx+1); + with oper[opidx]^ do + begin + if typ<>top_conditioncode then + begin + clearop(opidx); + end; + cc:=c; + typ:=top_conditioncode; + end; + end; + + {***************************************************************************** taicpu Constructors *****************************************************************************} @@ -314,6 +335,16 @@ implementation end; + constructor taicpu.op_reg_const_shifterop(op: tasmop; _op1: tregister; _op2: aint; _op3: tshifterop); + begin + inherited create(op); + ops:=3; + loadreg(0,_op1); + loadconst(1,_op2); + loadshifterop(2,_op3); + end; + + constructor taicpu.op_reg_ref(op : tasmop;_op1 : tregister;const _op2 : treference); begin inherited create(op); @@ -323,6 +354,15 @@ implementation end; + constructor taicpu.op_reg_cond(op: tasmop; _op1: tregister; _op2: tasmcond); + begin + inherited create(op); + ops:=2; + loadreg(0,_op1); + loadconditioncode(1,_op2); + end; + + constructor taicpu.op_reg_reg_reg(op : tasmop;_op1,_op2,_op3 : tregister); begin inherited create(op); @@ -354,6 +394,28 @@ implementation 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,aint(_op3)); + loadconst(3,aint(_op4)); + end; + + + constructor taicpu.op_reg_reg_const_shifterop(op: tasmop; _op1, _op2: tregister; _op3: aint; const _op4: tshifterop); + begin + inherited create(op); + ops:=4; + loadreg(0,_op1); + loadreg(1,_op2); + loadconst(2,aint(_op3)); + loadshifterop(3,_op4); + end; + + constructor taicpu.op_reg_reg_sym_ofs(op : tasmop;_op1,_op2 : tregister; _op3: tasmsymbol;_op3ofs: longint); begin inherited create(op); @@ -384,7 +446,7 @@ implementation end; - constructor taicpu.op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister;_op4 : tshifterop); + constructor taicpu.op_reg_reg_reg_shifterop(op : tasmop;_op1,_op2,_op3 : tregister; const _op4 : tshifterop); begin inherited create(op); ops:=4; @@ -394,6 +456,16 @@ implementation loadshifterop(3,_op4); end; + constructor taicpu.op_reg_reg_reg_cond(op: tasmop; _op1, _op2, _op3: tregister; const _op4: tasmcond); + begin + inherited create(op); + ops:=4; + loadreg(0,_op1); + loadreg(1,_op2); + loadreg(2,_op3); + loadconditioncode(3,_op4); + end; + constructor taicpu.op_cond_sym(op : tasmop;cond:TAsmCond;_op1 : tasmsymbol); begin @@ -454,85 +526,403 @@ implementation end; - function spilling_create_load(const ref:treference;r:tregister):Taicpu; + function spilling_create_op(op: tasmop; const ref: treference; r: tregister): taicpu; + const + { invalid sizes for aarch64 are 0 } + subreg2bytesize: array[TSubRegister] of byte = + (0,0,0,0,4,8,0,0,0,4,8,0,0,0); var - op: tasmop; + scalefactor: byte; begin + scalefactor:=subreg2bytesize[getsubreg(r)]; + if scalefactor=0 then + internalerror(2014120301); + if (ref.offset>4095*scalefactor) or + ((ref.offset>255) and + ((ref.offset mod scalefactor)<>0)) or + (ref.offset<-256) then + internalerror(2014120302); case getregtype(r) of - R_INTREGISTER : - result:=taicpu.op_reg_ref(A_LDR,r,ref); - R_MMREGISTER : - begin - case getsubreg(r) of - R_SUBFD: - op:=A_LDR; - R_SUBFS: - op:=A_LDR; - else - internalerror(2009112905); - end; - result:=taicpu.op_reg_ref(op,r,ref); - end; + R_INTREGISTER, + R_MMREGISTER: + result:=taicpu.op_reg_ref(op,r,ref); else internalerror(200401041); end; end; - function spilling_create_store(r:tregister; const ref:treference):Taicpu; + function is_valid_load_symbol(op: tasmop; oppostfix: toppostfix; const ref: treference): tsimplereftype; + begin + result:=sr_complex; + if not assigned(ref.symboldata) and + not(ref.refaddr in [addr_gotpageoffset,addr_gotpage,addr_pageoffset,addr_page]) then + exit; + { can't use pre-/post-indexed mode here (makes no sense either) } + if ref.addressmode<>AM_OFFSET then + exit; + { "ldr literal" must be a 32/64 bit LDR and have a symbol } + if assigned(ref.symboldata) and + ((op<>A_LDR) or + not(oppostfix in [PF_NONE,PF_W,PF_SW]) or + not assigned(ref.symbol)) then + exit; + { if this is a (got) page offset load, we must have a base register and a + symbol } + if (ref.refaddr in [addr_gotpageoffset,addr_pageoffset]) and + (not assigned(ref.symbol) or + (ref.base=NR_NO) or + (ref.index<>NR_NO) or + (ref.offset<>0)) then + begin + result:=sr_internal_illegal; + exit; + end; + { cannot have base or index register (we generate these kind of + references internally, they should never end up here with an + extra base or offset) } + if (ref.refaddr in [addr_gotpage,addr_page]) and + (ref.base<>NR_NO) or + (ref.index<>NR_NO) then + begin + result:=sr_internal_illegal; + exit; + end; + result:=sr_simple; + end; + + + function simple_ref_type(op: tasmop; size:tcgsize; oppostfix: toppostfix; const ref: treference): tsimplereftype; var - op: tasmop; + maxoffs: asizeint; + accesssize: longint; begin - case getregtype(r) of - R_INTREGISTER : - result:=taicpu.op_reg_ref(A_STR,r,ref); - R_MMREGISTER : - begin - case getsubreg(r) of - R_SUBFD: - op:=A_STR; - R_SUBFS: - op:=A_STR; + result:=sr_internal_illegal; + { post-indexed is only allowed for vector and immediate loads/stores } + if (ref.addressmode=AM_POSTINDEXED) and + not(op in [A_LD1,A_LD2,A_LD3,A_LD4,A_ST1,A_ST2,A_ST3,A_ST4]) and + (not(op in [A_LDR,A_STR,A_LDP,A_STP]) or + (ref.base=NR_NO) or + (ref.index<>NR_NO)) then + exit; + + { can only have a shift mode if we have an index } + if (ref.index=NR_NO) and + (ref.shiftmode<>SM_None) then + exit; + + { the index can never be the stack pointer } + if ref.index=NR_SP then + exit; + + { no instruction supports an index without a base } + if (ref.base=NR_NO) and + (ref.index<>NR_NO) then + begin + result:=sr_complex; + exit; + end; + + { LDR literal or GOT entry: 32 or 64 bit, label } + if assigned(ref.symboldata) or + assigned(ref.symbol) then + begin + { we generate these kind of references internally; at least for now, + they should never end up here with an extra base or offset or so } + result:=is_valid_load_symbol(op,oppostfix,ref); + exit; + end; + + { any other reference cannot be gotpage/gotpageoffset/pic } + if ref.refaddr in [addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset,addr_pic] then + exit; + + { base & index: + * index cannot be the stack pointer + * offset must be 0 + * can scale with the size of the access + * can zero/sign extend 32 bit index register, and/or multiple by + access size + * no pre/post-indexing + } + if (ref.base<>NR_NO) and + (ref.index<>NR_NO) then + begin + if ref.addressmode in [AM_PREINDEXED,AM_POSTINDEXED] then + exit; + case op of + { this holds for both integer and fpu/vector loads } + A_LDR,A_STR: + if (ref.offset=0) and + (((ref.shiftmode=SM_None) and + (ref.shiftimm=0)) or + ((ref.shiftmode in [SM_LSL,SM_UXTW,SM_SXTW]) and + (ref.shiftimm=tcgsizep2size[size]))) then + result:=sr_simple else - internalerror(2009112904); - end; - result:=taicpu.op_reg_ref(op,r,ref); + result:=sr_complex; + { todo } + A_LD1,A_LD2,A_LD3,A_LD4, + A_ST1,A_ST2,A_ST3,A_ST4: + internalerror(2014110704); + { these don't support base+index } + A_LDUR,A_STUR, + A_LDP,A_STP: + result:=sr_complex; + else + { nothing: result is already sr_internal_illegal }; end; + exit; + end; + + { base + immediate offset. Variants: + * LDR*/STR*: + - pre- or post-indexed with signed 9 bit immediate + - regular with unsiged scaled immediate (multiple of access + size), in the range 0 to (12 bit * access_size)-1 + * LDP/STP + - pre- or post-indexed with signed 9 bit immediate + - regular with signed 9 bit immediate + * LDUR*/STUR*: + - regular with signed 9 bit immediate + } + if ref.base<>NR_NO then + begin + accesssize:=1 shl tcgsizep2size[size]; + case op of + A_LDR,A_STR: + begin + if (ref.addressmode=AM_OFFSET) and + (ref.offset>=0) and + (ref.offset<(((1 shl 12)-1)*accesssize)) and + ((ref.offset mod accesssize)=0) then + result:=sr_simple + else if (ref.offset>=-256) and + (ref.offset<=255) then + begin + { non pre-/post-indexed regular loads/stores can only be + performed using LDUR/STUR } + if ref.addressmode in [AM_PREINDEXED,AM_POSTINDEXED] then + result:=sr_simple + else + result:=sr_complex + end + else + result:=sr_complex; + end; + A_LDP,A_LDNP, + A_STP,A_STNP: + begin + { only supported for 32/64 bit } + if not(oppostfix in [PF_W,PF_SW,PF_None]) then + exit; + { offset must be a multple of the access size } + if (ref.offset mod accesssize)<>0 then + exit; + { offset must fit in a signed 7 bit offset } + if (ref.offset>=-(1 shl (6+tcgsizep2size[size]))) and + (ref.offset<=(1 shl (6+tcgsizep2size[size]))-1) then + result:=sr_simple + else + result:=sr_complex; + end; + A_LDUR,A_STUR: + begin + if (ref.addressmode=AM_OFFSET) and + (ref.offset>=-256) and + (ref.offset<=255) then + result:=sr_simple + else + result:=sr_complex; + end; + { todo } + A_LD1,A_LD2,A_LD3,A_LD4, + A_ST1,A_ST2,A_ST3,A_ST4: + internalerror(2014110907); + A_LDAR, + A_LDAXR, + A_LDXR, + A_LDXP, + A_STLR, + A_STLXR, + A_STLXP, + A_STXP, + A_STXR: + begin + if (ref.addressmode=AM_OFFSET) and + (ref.offset=0) then + result:=sr_simple; + end + else + { nothing: result is already sr_internal_illegal }; + end; + exit; + end; + { absolute addresses are not supported, have to load them first into + a register } + result:=sr_complex; + end; + + + function can_be_shifter_operand(opc: tasmop; opnr: longint): boolean; + begin + case opc of + A_ADD, + A_AND, + A_EON, + A_EOR, + A_ORN, + A_ORR, + A_SUB: + result:=opnr=3; + A_BIC, + A_CMN, + A_CMP, + A_MOVK, + A_MOVZ, + A_MOVN, + A_MVN, + A_NEG, + A_TST: + result:=opnr=2; else - internalerror(200401041); + result:=false; end; end; + function valid_shifter_operand(opc: tasmop; useszr, usessp, is64bit: boolean; sm: tshiftmode; shiftimm: longint): boolean; + begin + case opc of + A_ADD, + A_SUB, + A_NEG, + A_AND, + A_TST, + A_CMN, + A_CMP: + begin + result:=false; + if not useszr then + result:= + (sm in shiftedregmodes) and + ((shiftimm in [0..31]) or + (is64bit and + (shiftimm in [32..63]))); + if not usessp then + result:= + result or + ((sm in extendedregmodes) and + (shiftimm in [0..4])); + end; + A_BIC, + A_EON, + A_EOR, + A_MVN, + A_ORN, + A_ORR: + result:= + (sm in shiftedregmodes) and + (shiftimm in [0..31*(ord(is64bit)+1)+ord(is64bit)]); + A_MOVK, + A_MOVZ, + A_MOVN: + result:= + (sm=SM_LSL) and + ((shiftimm in [0,16]) or + (is64bit and + (shiftimm in [32,48]))); + else + result:=false; + end; + end; + + + function spilling_create_load(const ref: treference; r: tregister): taicpu; + var + op: tasmop; + begin + if (ref.index<>NR_NO) or + (ref.offset<-256) or + (ref.offset>255) then + op:=A_LDR + else + op:=A_LDUR; + result:=spilling_create_op(op,ref,r); + end; + + + function spilling_create_store(r: tregister; const ref: treference): taicpu; + var + op: tasmop; + begin + if (ref.index<>NR_NO) or + (ref.offset<-256) or + (ref.offset>255) then + op:=A_STR + else + op:=A_STUR; + result:=spilling_create_op(op,ref,r); + end; + + function taicpu.spilling_get_operation_type(opnr: longint): topertype; begin case opcode of - A_ADC,A_ADD,A_AND,A_BIC, - A_EOR,A_CLZ,A_RBIT, - A_LDR, - A_MOV,A_MVN,A_MUL, - A_ORR,A_SBC,A_SUB, - A_UXT,A_SXT: + A_B,A_BL, + A_CMN,A_CMP, + A_CCMN,A_CCMP, + A_TST: + result:=operand_read; + A_STR,A_STUR: if opnr=0 then - result:=operand_write + result:=operand_read else + { check for pre/post indexed in spilling_get_operation_type_ref } result:=operand_read; - A_B,A_BL, - A_CMN,A_CMP,A_TST: - result:=operand_read; - A_STR: - { important is what happens with the involved registers } + A_STLXP, + A_STLXR, + A_STXP, + A_STXR: if opnr=0 then - result := operand_read + result:=operand_write else - { check for pre/post indexed } - result := operand_read; - else - internalerror(200403151); + result:=operand_read; + A_STP: + begin + if opnr in [0,1] then + result:=operand_read + else + { check for pre/post indexed in spilling_get_operation_type_ref } + result:=operand_read; + end; + A_LDP, + A_LDXP: + begin + if opnr in [0,1] then + result:=operand_write + else + { check for pre/post indexed in spilling_get_operation_type_ref } + result:=operand_read; + end; + else + if opnr=0 then + result:=operand_write + else + result:=operand_read; end; end; + function taicpu.spilling_get_operation_type_ref(opnr: longint; reg: tregister): topertype; + begin + result:=operand_read; + if (oper[opnr]^.ref^.base = reg) and + (oper[opnr]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) then + result:=operand_readwrite; + end; + + procedure BuildInsTabCache; var i : longint; @@ -1069,22 +1459,12 @@ implementation { we need to reset everything here, because the choosen insentry can be invalid for a new situation where the previously optimized insentry is not correct } - InsEntry:=nil; - InsSize:=0; - LastInsOffset:=-1; end; procedure taicpu.ResetPass2; begin { we are here in a second pass, check if the instruction can be optimized } - if assigned(InsEntry) and - ((InsEntry^.flags and IF_PASS2)<>0) then - begin - InsEntry:=nil; - InsSize:=0; - end; - LastInsOffset:=-1; end; @@ -1097,18 +1477,15 @@ implementation function taicpu.Pass1(objdata:TObjData):longint; begin Pass1:=0; - LastInsOffset:=-1; end; procedure taicpu.Pass2(objdata:TObjData); begin { error in pass1 ? } - if insentry=nil then - exit; current_filepos:=fileinfo; { Generate the instruction } - GenCode(objdata); + { GenCode(objdata); } end; @@ -1132,1046 +1509,6 @@ implementation end; - function taicpu.InsEnd:longint; - begin - Result:=0; { unimplemented } - end; - - - procedure taicpu.create_ot(objdata:TObjData); - begin - end; - - - function taicpu.Matches(p:PInsEntry):longint; - begin - end; - - - function taicpu.calcsize(p:PInsEntry):shortint; - begin - result:=4; - end; - - - function taicpu.NeedAddrPrefix(opidx:byte):boolean; - begin - Result:=False; { unimplemented } - end; - - - procedure taicpu.Swapoperands; - begin - end; - - - function taicpu.FindInsentry(objdata:TObjData):boolean; - begin - end; - - - procedure taicpu.gencode(objdata:TObjData); - var - bytes : dword; - i_field : byte; - - procedure setshifterop(op : byte); - begin - case oper[op]^.typ of - top_const: - begin - i_field:=1; - bytes:=bytes or dword(oper[op]^.val and $fff); - end; - top_reg: - begin - i_field:=0; - bytes:=bytes or (getsupreg(oper[op]^.reg) shl 16); - - { does a real shifter op follow? } - if (op+1<=op) and (oper[op+1]^.typ=top_shifterop) then - begin - end; - end; - else - internalerror(2005091103); - end; - end; - - begin - bytes:=$0; - { evaluate and set condition code } - - { condition code allowed? } - - { setup rest of the instruction } - case insentry^.code[0] of - #$08: - begin - { set instruction code } - bytes:=bytes or (ord(insentry^.code[1]) shl 26); - bytes:=bytes or (ord(insentry^.code[2]) shl 21); - - { set destination } - bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); - - { create shifter op } - setshifterop(1); - - { set i field } - bytes:=bytes or (i_field shl 25); - - { set s if necessary } - if oppostfix=PF_S then - bytes:=bytes or (1 shl 20); - end; - #$ff: - internalerror(2005091101); - else - internalerror(2005091102); - end; - { we're finished, write code } - objdata.writebytes(bytes,sizeof(bytes)); - end; - - -{$ifdef dummy} -(* -static void gencode (long segment, long offset, int bits, - insn *ins, char *codes, long insn_end) -{ - int has_S_code; /* S - setflag */ - int has_B_code; /* B - setflag */ - int has_T_code; /* T - setflag */ - int has_W_code; /* ! => W flag */ - int has_F_code; /* ^ => S flag */ - int keep; - unsigned char c; - unsigned char bytes[4]; - long data, size; - static int cc_code[] = /* bit pattern of cc */ - { /* order as enum in */ - 0x0E, 0x03, 0x02, 0x00, /* nasm.h */ - 0x0A, 0x0C, 0x08, 0x0D, - 0x09, 0x0B, 0x04, 0x01, - 0x05, 0x07, 0x06, - }; - - -#ifdef DEBUG -static char *CC[] = - { /* condition code names */ - "AL", "CC", "CS", "EQ", - "GE", "GT", "HI", "LE", - "LS", "LT", "MI", "NE", - "PL", "VC", "VS", "", - "S" -}; - - - has_S_code = (ins->condition & C_SSETFLAG); - has_B_code = (ins->condition & C_BSETFLAG); - has_T_code = (ins->condition & C_TSETFLAG); - has_W_code = (ins->condition & C_EXSETFLAG); - has_F_code = (ins->condition & C_FSETFLAG); - ins->condition = (ins->condition & 0x0F); - - - if (rt_debug) - { - printf ("gencode: instruction: %s%s", insn_names[ins->opcode], - CC[ins->condition & 0x0F]); - if (has_S_code) - printf ("S"); - if (has_B_code) - printf ("B"); - if (has_T_code) - printf ("T"); - if (has_W_code) - printf ("!"); - if (has_F_code) - printf ("^"); - - printf ("\n"); - - c = *codes; - - printf (" (%d) decode - '0x%02X'\n", ins->operands, c); - - - bytes[0] = 0xB; - bytes[1] = 0xE; - bytes[2] = 0xE; - bytes[3] = 0xF; - } - - // First condition code in upper nibble - if (ins->condition < C_NONE) - { - c = cc_code[ins->condition] << 4; - } - else - { - c = cc_code[C_AL] << 4; // is often ALWAYS but not always - } - - - switch (keep = *codes) - { - case 1: - // B, BL - ++codes; - c |= *codes++; - bytes[0] = c; - - if (ins->oprs[0].segment != segment) - { - // fais une relocation - c = 1; - data = 0; // Let the linker locate ?? - } - else - { - c = 0; - data = ins->oprs[0].offset - (offset + 8); - - if (data % 4) - { - errfunc (ERR_NONFATAL, "offset not aligned on 4 bytes"); - } - } - - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - - data = data >> 2; - bytes[1] = (data >> 16) & 0xFF; - bytes[2] = (data >> 8) & 0xFF; - bytes[3] = (data ) & 0xFF; - - if (c == 1) - { -// out (offset, segment, &bytes[0], OUT_RAWDATA+1, NO_SEG, NO_SEG); - out (offset, segment, &bytes[0], OUT_REL3ADR+4, ins->oprs[0].segment, NO_SEG); - } - else - { - out (offset, segment, &bytes[0], OUT_RAWDATA+4, NO_SEG, NO_SEG); - } - return; - - case 2: - // SWI - ++codes; - c |= *codes++; - bytes[0] = c; - data = ins->oprs[0].offset; - bytes[1] = (data >> 16) & 0xFF; - bytes[2] = (data >> 8) & 0xFF; - bytes[3] = (data) & 0xFF; - out (offset, segment, &bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - case 3: - // BX - ++codes; - c |= *codes++; - bytes[0] = c; - bytes[1] = *codes++; - bytes[2] = *codes++; - bytes[3] = *codes++; - c = regval (&ins->oprs[0],1); - if (c == 15) // PC - { - errfunc (ERR_WARNING, "'BX' with R15 has undefined behaviour"); - } - else if (c > 15) - { - errfunc (ERR_NONFATAL, "Illegal register specified for 'BX'"); - } - - bytes[3] |= (c & 0x0F); - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - case 4: // AND Rd,Rn,Rm - case 5: // AND Rd,Rn,Rm,Rs - case 6: // AND Rd,Rn,Rm,imm - case 7: // AND Rd,Rn,imm - ++codes; -#ifdef DEBUG - if (rt_debug) - { - printf (" decode - '0x%02X'\n", keep); - printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); - } -#endif - bytes[0] = c | *codes; - ++codes; - - bytes[1] = *codes; - if (has_S_code) - bytes[1] |= 0x10; - c = regval (&ins->oprs[1],1); - // Rn in low nibble - bytes[1] |= c; - - // Rd in high nibble - bytes[2] = regval (&ins->oprs[0],1) << 4; - - if (keep != 7) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[2],1); - } - - // Shifts if any - if (keep == 5 || keep == 6) - { - // Shift in bytes 2 and 3 - if (keep == 5) - { - // Rs - c = regval (&ins->oprs[3],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 6) - { - c = (ins->oprs[3].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[3]) << 5; - - bytes[3] |= c; - } - - // reg,reg,imm - if (keep == 7) - { - int shimm; - - shimm = imm_shift (ins->oprs[2].offset); - - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } - - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - case 8: // MOV Rd,Rm - case 9: // MOV Rd,Rm,Rs - case 0xA: // MOV Rd,Rm,imm - case 0xB: // MOV Rd,imm - ++codes; -#ifdef DEBUG - if (rt_debug) - { - printf (" decode - '0x%02X'\n", keep); - printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); - } -#endif - bytes[0] = c | *codes; - ++codes; - - bytes[1] = *codes; - if (has_S_code) - bytes[1] |= 0x10; - - // Rd in high nibble - bytes[2] = regval (&ins->oprs[0],1) << 4; - - if (keep != 0x0B) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[1],1); - } - - // Shifts if any - if (keep == 0x09 || keep == 0x0A) - { - // Shift in bytes 2 and 3 - if (keep == 0x09) - { - // Rs - c = regval (&ins->oprs[2],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 0x0A) - { - c = (ins->oprs[2].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[2]) << 5; - - bytes[3] |= c; - } - - // reg,imm - if (keep == 0x0B) - { - int shimm; - - shimm = imm_shift (ins->oprs[1].offset); - - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } - - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - - case 0xC: // CMP Rn,Rm - case 0xD: // CMP Rn,Rm,Rs - case 0xE: // CMP Rn,Rm,imm - case 0xF: // CMP Rn,imm - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes; - - // Implicit S code - bytes[1] |= 0x10; - - c = regval (&ins->oprs[0],1); - // Rn in low nibble - bytes[1] |= c; - - // No destination - bytes[2] = 0; - - if (keep != 0x0B) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[1],1); - } - - // Shifts if any - if (keep == 0x0D || keep == 0x0E) - { - // Shift in bytes 2 and 3 - if (keep == 0x0D) - { - // Rs - c = regval (&ins->oprs[2],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 0x0E) - { - c = (ins->oprs[2].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[2]) << 5; - - bytes[3] |= c; - } - - // reg,imm - if (keep == 0x0F) - { - int shimm; - - shimm = imm_shift (ins->oprs[1].offset); - - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } - - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - case 0x10: // MRS Rd, - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - // Rd - c = regval (&ins->oprs[0],1); - - bytes[2] = c << 4; - - bytes[3] = 0; - - c = ins->oprs[1].basereg; - - if (c == R_CPSR || c == R_SPSR) - { - if (c == R_SPSR) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR or SPSR expected"); - } - - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - - return; - - case 0x11: // MSR ,Rm - case 0x12: // MSR ,Rm - case 0x13: // MSR ,#expression - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - bytes[2] = *codes; - - - if (keep == 0x11 || keep == 0x12) - { - // Rm - c = regval (&ins->oprs[1],1); - - bytes[3] = c; - } - else - { - int shimm; - - shimm = imm_shift (ins->oprs[1].offset); - - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } - - c = ins->oprs[0].basereg; - - if ( keep == 0x11) - { - if ( c == R_CPSR || c == R_SPSR) - { - if ( c== R_SPSR) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR or SPSR expected"); - } - } - else - { - if ( c == R_CPSR_FLG || c == R_SPSR_FLG) - { - if ( c== R_SPSR_FLG) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR_flg or SPSR_flg expected"); - } - } - break; - - case 0x14: // MUL Rd,Rm,Rs - case 0x15: // MULA Rd,Rm,Rs,Rn - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - bytes[3] = *codes; - - // Rd - bytes[1] |= regval (&ins->oprs[0],1); - if (has_S_code) - bytes[1] |= 0x10; - - // Rm - bytes[3] |= regval (&ins->oprs[1],1); - - // Rs - bytes[2] = regval (&ins->oprs[2],1); - - if (keep == 0x15) - { - bytes[2] |= regval (&ins->oprs[3],1) << 4; - } - break; - - case 0x16: // SMLAL RdHi,RdLo,Rm,Rs - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - bytes[3] = *codes; - - // RdHi - bytes[1] |= regval (&ins->oprs[1],1); - if (has_S_code) - bytes[1] |= 0x10; - - // RdLo - bytes[2] = regval (&ins->oprs[0],1) << 4; - // Rm - bytes[3] |= regval (&ins->oprs[2],1); - - // Rs - bytes[2] |= regval (&ins->oprs[3],1); - - break; - - case 0x17: // LDR Rd, expression - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - if (has_T_code) - { - errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode"); - } - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed"); - } - - // Rn - implicit R15 - bytes[1] |= 0xF; - - if (ins->oprs[1].segment != segment) - { - errfunc (ERR_NONFATAL, "label not in same segment"); - } - - data = ins->oprs[1].offset - (offset + 8); - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - break; - - case 0x18: // LDR Rd, [Rn] - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - if (has_T_code) - { - bytes[1] |= 0x20; // write-back - } - else - { - bytes[0] |= 0x01; // implicit pre-index mode - } - - if (has_W_code) - { - bytes[1] |= 0x20; // write-back - } - - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; - - if (c == 0x15) // R15 - data = -8; - else - data = 0; - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - break; - - case 0x19: // LDR Rd, [Rn,#expression] - case 0x20: // LDR Rd, [Rn,Rm] - case 0x21: // LDR Rd, [Rn,Rm,shift] - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; - - if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <-- - { - bytes[0] |= 0x01; // pre-index mode - if (has_W_code) - { - bytes[1] |= 0x20; - } - if (has_T_code) - { - errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode"); - } - } - else - { - if (has_T_code) // Forced write-back in post-index mode - { - bytes[1] |= 0x20; - } - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode"); - } - } - - if (keep == 0x19) - { - data = ins->oprs[2].offset; - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - } - else - { - if (ins->oprs[2].minus == 0) - { - bytes[1] |= 0x80; - } - c = regval (&ins->oprs[2],1); - bytes[3] = c; - - if (keep == 0x21) - { - c = ins->oprs[3].offset; - if (c > 0x1F) - { - errfunc (ERR_NONFATAL, "too large shiftvalue"); - c = c & 0x1F; - } - - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - bytes[3] |= shiftval (&ins->oprs[3]) << 5; - } - } - - break; - - case 0x22: // LDRH Rd, expression - ++codes; - - bytes[0] = c | 0x01; // Implicit pre-index - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - - // Rn - implicit R15 - bytes[1] |= 0xF; - - if (ins->oprs[1].segment != segment) - { - errfunc (ERR_NONFATAL, "label not in same segment"); - } - - data = ins->oprs[1].offset - (offset + 8); - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - bytes[3] = *codes++; - - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - break; - - case 0x23: // LDRH Rd, Rn - ++codes; - - bytes[0] = c | 0x01; // Implicit pre-index - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; - - if (c == 0x15) // R15 - data = -8; - else - data = 0; - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - bytes[3] = *codes++; - - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - break; - - case 0x24: // LDRH Rd, Rn, expression - case 0x25: // LDRH Rd, Rn, Rm - ++codes; - - bytes[0] = c; - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; - - if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <-- - { - bytes[0] |= 0x01; // pre-index mode - if (has_W_code) - { - bytes[1] |= 0x20; - } - } - else - { - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode"); - } - } - - bytes[3] = *codes++; - - if (keep == 0x24) - { - data = ins->oprs[2].offset; - - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } - - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - } - else - { - if (ins->oprs[2].minus == 0) - { - bytes[1] |= 0x80; - } - c = regval (&ins->oprs[2],1); - bytes[3] |= c; - - } - break; - - case 0x26: // LDM/STM Rn, {reg-list} - ++codes; - - bytes[0] = c; - - bytes[0] |= ( *codes >> 4) & 0xF; - bytes[1] = ( *codes << 4) & 0xF0; - ++codes; - - if (has_W_code) - { - bytes[1] |= 0x20; - } - if (has_F_code) - { - bytes[1] |= 0x40; - } - - // Rn - bytes[1] |= regval (&ins->oprs[0],1); - - data = ins->oprs[1].basereg; - - bytes[2] = ((data >> 8) & 0xFF); - bytes[3] = (data & 0xFF); - - break; - - case 0x27: // SWP Rd, Rm, [Rn] - ++codes; - - bytes[0] = c; - - bytes[0] |= *codes++; - - bytes[1] = regval (&ins->oprs[2],1); - if (has_B_code) - { - bytes[1] |= 0x40; - } - bytes[2] = regval (&ins->oprs[0],1) << 4; - bytes[3] = *codes++; - bytes[3] |= regval (&ins->oprs[1],1); - break; - - default: - errfunc (ERR_FATAL, "unknown decoding of instruction"); - - bytes[0] = c; - // And a fix nibble - ++codes; - bytes[0] |= *codes++; - - if ( *codes == 0x01) // An I bit - { - - } - if ( *codes == 0x02) // An I bit - { - - } - ++codes; - } - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); -} - -*) -{$endif dummy} - begin cai_align:=tai_align; end. diff --git a/fpcsrc/compiler/aarch64/agcpugas.pas b/fpcsrc/compiler/aarch64/agcpugas.pas new file mode 100644 index 00000000..1782f644 --- /dev/null +++ b/fpcsrc/compiler/aarch64/agcpugas.pas @@ -0,0 +1,303 @@ +{ + Copyright (c) 2003,2014 by Florian Klaempfl and Jonas Maebe + + This unit implements an asm for AArch64 + + 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 implements the GNU Assembler writer for AArch64 +} + +unit agcpugas; + +{$i fpcdefs.inc} + + interface + + uses + globtype, + aasmtai, + aggas, + cpubase,cpuinfo; + + type + TAArch64InstrWriter=class(TCPUInstrWriter) + procedure WriteInstruction(hp : tai);override; + end; + + TAArch64Assembler=class(TGNUassembler) + constructor create(smart: boolean); override; + end; + + TAArch64AppleAssembler=class(TAppleGNUassembler) + constructor create(smart: boolean); override; + end; + + + const + gas_shiftmode2str : array[tshiftmode] of string[4] = ( + '','lsl','lsr','asr', + 'uxtb','uxth','uxtw','uxtx', + 'sxtb','sxth','sxtw','sxtx'); + + const + cputype_to_gas_march : array[tcputype] of string = ( + '', // cpu_none + 'armv8' + ); + + implementation + + uses + cutils,globals,verbose, + systems, + assemble, + aasmcpu, + itcpugas, + cgbase,cgutils; + + +{****************************************************************************} +{ AArch64 Assembler writer } +{****************************************************************************} + + constructor TAArch64Assembler.create(smart: boolean); + begin + inherited create(smart); + InstrWriter := TAArch64InstrWriter.create(self); + end; + +{****************************************************************************} +{ Apple AArch64 Assembler writer } +{****************************************************************************} + + constructor TAArch64AppleAssembler.create(smart: boolean); + begin + inherited create(smart); + InstrWriter := TAArch64InstrWriter.create(self); + end; + + +{****************************************************************************} +{ Helper routines for Instruction Writer } +{****************************************************************************} + + function getreferencestring(var ref : treference) : string; + const + darwin_addrpage2str: array[addr_page..addr_gotpageoffset] of string[11] = + ('@PAGE','@PAGEOFF','@GOTPAGE','@GOTPAGEOFF'); + linux_addrpage2str: array[addr_page..addr_gotpageoffset] of string[10] = + ('',':lo12:',':got:',':got_lo12:'); + begin + if ref.base=NR_NO then + begin + case ref.refaddr of + addr_gotpage, + addr_page, + addr_gotpageoffset, + addr_pageoffset: + begin + if not assigned(ref.symbol) or + (ref.base<>NR_NO) or + (ref.index<>NR_NO) or + (ref.shiftmode<>SM_None) or + (ref.offset<>0) then + internalerror(2014121501); + if target_info.system in systems_darwin then + result:=ref.symbol.name+darwin_addrpage2str[ref.refaddr] + else + result:=linux_addrpage2str[ref.refaddr]+ref.symbol.name + end + else + internalerror(2015022301); + end + end + else + begin + result:='['+gas_regname(ref.base); + if ref.addressmode=AM_POSTINDEXED then + result:=result+']'; + if ref.index<>NR_NO then + begin + if (ref.offset<>0) or + assigned(ref.symbol) then + internalerror(2014121504); + result:=result+', '+gas_regname(ref.index); + case ref.shiftmode of + SM_None: ; + SM_LSL, + SM_UXTW, SM_UXTX, SM_SXTW, SM_SXTX: + begin + result:=result+', '+gas_shiftmode2str[ref.shiftmode]; + if (ref.shiftmode=SM_LSL) or + (ref.shiftimm<>0) then + result:=result+' #'+tostr(ref.shiftimm); + end + else + internalerror(2014121505); + end; + end + else + begin + if assigned(ref.symbol) then + begin + case ref.refaddr of + addr_gotpageoffset, + addr_pageoffset: + begin + if target_info.system in systems_darwin then + result:=result+', '+ref.symbol.name+darwin_addrpage2str[ref.refaddr] + else + result:=result+', '+linux_addrpage2str[ref.refaddr]+ref.symbol.name + end + else + { todo: not yet generated/don't know syntax } + internalerror(2014121506); + end; + end + else + begin + if ref.refaddr<>addr_no then + internalerror(2014121506); + if (ref.offset<>0) then + result:=result+', #'+tostr(ref.offset); + end; + end; + case ref.addressmode of + AM_OFFSET: + result:=result+']'; + AM_PREINDEXED: + result:=result+']!'; + end; + end; + end; + + + function getopstr(hp: taicpu; opnr: longint; const o: toper): string; + begin + case o.typ of + top_reg: + { we cannot yet represent "umov w0, v4.s[0]" or "ins v4.d[0], x1", + so for now we use "s4" or "d4" instead -> translate here } + if ((hp.opcode=A_INS) or + (hp.opcode=A_UMOV)) and + (getregtype(hp.oper[opnr]^.reg)=R_MMREGISTER) then + begin + case getsubreg(hp.oper[opnr]^.reg) of + R_SUBMMS: + getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.S[0]'; + R_SUBMMD: + getopstr:='v'+tostr(getsupreg(hp.oper[opnr]^.reg))+'.D[0]'; + else + internalerror(2014122907); + end; + end + else + getopstr:=gas_regname(o.reg); + top_shifterop: + begin + getopstr:=gas_shiftmode2str[o.shifterop^.shiftmode]; + if o.shifterop^.shiftimm<>0 then + getopstr:=getopstr+' #'+tostr(o.shifterop^.shiftimm) + end; + top_const: + if o.val>=0 then + getopstr:='#'+tostr(o.val) + else + getopstr:='#0x'+hexStr(o.val,16); + top_conditioncode: + getopstr:=cond2str[o.cc]; + top_ref: + if is_calljmp(hp.opcode) then + begin + if o.ref^.refaddr<>addr_full then + internalerror(2014122220); + if not assigned(o.ref^.symbol) or + assigned(o.ref^.relsymbol) or + (o.ref^.base<>NR_NO) or + (o.ref^.index<>NR_NO) or + (o.ref^.offset<>0) then + internalerror(2014122221); + getopstr:=o.ref^.symbol.name; + end + else + getopstr:=getreferencestring(o.ref^); + else + internalerror(2014121507); + end; + end; + + + procedure TAArch64InstrWriter.WriteInstruction(hp : tai); + var + op: TAsmOp; + s: string; + i: byte; + sep: string[3]; + begin + op:=taicpu(hp).opcode; + s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix]; + if taicpu(hp).condition<>C_NONE then + s:=s+'.'+cond2str[taicpu(hp).condition]; + if taicpu(hp).ops<>0 then + begin + sep:=#9; + for i:=0 to taicpu(hp).ops-1 do + begin + // debug code + // writeln(s); + // writeln(taicpu(hp).fileinfo.line); + s:=s+sep+getopstr(taicpu(hp),i,taicpu(hp).oper[i]^); + sep:=','; + end; + end; + owner.AsmWriteLn(s); + end; + + + const + as_aarch64_gas_info : tasminfo = + ( + id : as_gas; + idtxt : 'AS'; + asmbin : 'as'; + asmcmd : '-o $OBJ $EXTRAOPT $ASM'; + supported_targets : [system_aarch64_linux]; + flags : [af_needar,af_smartlink_sections]; + labelprefix : '.L'; + comment : '// '; + dollarsign: '$'; + ); + + as_aarch64_clang_darwin_info : tasminfo = + ( + id : as_clang; + idtxt : 'CLANG'; + asmbin : 'clang'; + asmcmd : '-c -o $OBJ $EXTRAOPT -arch arm64 $DARWINVERSION -x assembler $ASM'; + supported_targets : [system_aarch64_darwin]; + flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; + labelprefix : 'L'; + comment : '# '; + dollarsign: '$'; + ); + + +begin + RegisterAssembler(as_aarch64_gas_info,TAArch64Assembler); + RegisterAssembler(as_aarch64_clang_darwin_info,TAArch64AppleAssembler); +end. diff --git a/fpcsrc/compiler/aarch64/aoptcpub.pas b/fpcsrc/compiler/aarch64/aoptcpub.pas index d3964a02..d4fbac69 100644 --- a/fpcsrc/compiler/aarch64/aoptcpub.pas +++ b/fpcsrc/compiler/aarch64/aoptcpub.pas @@ -118,17 +118,35 @@ Implementation End; - function TAoptBaseCpu.RegModifiedByInstruction(Reg: TRegister; p1: tai): boolean; + function TAoptBaseCpu.RegModifiedByInstruction(reg: tregister; p1: tai): boolean; var - i : Longint; + i: longint; + preg: tregister; begin result:=false; for i:=0 to taicpu(p1).ops-1 do - if (taicpu(p1).oper[i]^.typ=top_reg) and (taicpu(p1).oper[i]^.reg=Reg) and (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then - begin - result:=true; - exit; - end; + case taicpu(p1).oper[i]^.typ of + top_reg: + begin + preg:=taicpu(p1).oper[i]^.reg; + if (getregtype(preg)=getregtype(reg)) and + (getsupreg(preg)=getsupreg(reg)) and + (taicpu(p1).spilling_get_operation_type(i) in [operand_write,operand_readwrite]) then + begin + result:=true; + exit; + end; + end; + top_ref: + begin + if (taicpu(p1).oper[i]^.ref^.addressmode<>am_offset) and + (reg=taicpu(p1).oper[i]^.ref^.base) then + begin + result:=true; + exit + end; + end; + end; end; End. diff --git a/fpcsrc/compiler/aarch64/cgcpu.pas b/fpcsrc/compiler/aarch64/cgcpu.pas new file mode 100644 index 00000000..7faf7809 --- /dev/null +++ b/fpcsrc/compiler/aarch64/cgcpu.pas @@ -0,0 +1,2275 @@ +{ + Copyright (c) 2014 by Jonas Maebe + + This unit implements the code generator for AArch64 + + 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,parabase, + cgbase,cgutils,cgobj, + aasmbase,aasmtai,aasmdata,aasmcpu, + cpubase,cpuinfo, + node,symconst,SymType,symdef, + rgcpu; + + type + tcgaarch64=class(tcg) + protected + { simplifies "ref" so it can be used with "op". If "ref" can be used + with a different load/Store operation that has the same meaning as the + original one, "op" will be replaced with the alternative } + procedure make_simple_ref(list:TAsmList; var op: tasmop; size: tcgsize; oppostfix: toppostfix; var ref: treference; preferred_newbasereg: tregister); + { changes register size without adding register allocation info } + function makeregsize(reg: tregister; size: tcgsize): tregister; overload; + public + function getfpuregister(list: TAsmList; size: Tcgsize): Tregister; override; + procedure handle_reg_imm12_reg(list: TAsmList; op: Tasmop; size: tcgsize; src: tregister; a: tcgint; dst: tregister; tmpreg: tregister; setflags, usedest: boolean); + procedure init_register_allocators;override; + procedure done_register_allocators;override; + function getmmregister(list:TAsmList;size:tcgsize):tregister;override; + function handle_load_store(list:TAsmList; op: tasmop; size: tcgsize; oppostfix: toppostfix; reg: tregister; ref: treference):treference; + procedure a_call_name(list:TAsmList;const s:string; weak: boolean);override; + procedure a_call_reg(list:TAsmList;Reg:tregister);override; + { General purpose instructions } + procedure maybeadjustresult(list: TAsmList; op: topcg; size: tcgsize; dst: tregister); + 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_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; + { move instructions } + procedure a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; reg: tregister);override; + procedure a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); override; + procedure a_load_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister;const ref: TReference);override; + procedure a_load_reg_ref_unaligned(list: TAsmList; fromsize, tosize: tcgsize; register: tregister; const ref: treference); override; + procedure a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister);override; + procedure a_load_ref_reg_unaligned(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; register: tregister); override; + procedure a_load_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister);override; + procedure a_loadaddr_ref_reg(list: TAsmList; const ref: TReference; r: tregister);override; + { fpu move instructions (not used, all floating point is vector unit-based) } + 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 a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister;shuffle : pmmshuffle);override; + procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: TReference; reg: tregister; shuffle: pmmshuffle);override; + procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: TReference; shuffle: pmmshuffle);override; + + procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle); override; + procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; mmreg, intreg: tregister; shuffle: pmmshuffle); override; + + procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle); override; + + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override; + { comparison operations } + procedure a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);override; + procedure a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);override; + procedure a_jmp_always(list: TAsmList; l: TAsmLabel);override; + procedure a_jmp_name(list: TAsmList; const s: string);override; + procedure a_jmp_cond(list: TAsmList; cond: TOpCmp; l: tasmlabel);{ override;} + procedure a_jmp_flags(list: TAsmList; const f: tresflags; l: tasmlabel);override; + procedure g_flags2reg(list: TAsmList; size: tcgsize; const f:tresflags; reg: tregister);override; + procedure g_overflowcheck(list: TAsmList; const loc: tlocation; def: tdef);override; + procedure g_overflowcheck_loc(list: TAsmList; const loc: tlocation; def: tdef; ovloc: tlocation);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_maybe_got_init(list: TAsmList); override; + procedure g_restore_registers(list: TAsmList);override; + procedure g_save_registers(list: TAsmList);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_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: tcgint);override; + procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override; + private + function save_regs(list: TAsmList; rt: tregistertype; lowsr, highsr: tsuperregister; sub: tsubregister): longint; + procedure load_regs(list: TAsmList; rt: tregistertype; lowsr, highsr: tsuperregister; sub: tsubregister); + end; + + procedure create_codegen; + + const + TOpCG2AsmOpReg: array[topcg] of TAsmOp = ( + A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NEG,A_MVN,A_ORR,A_ASRV,A_LSLV,A_LSRV,A_SUB,A_EOR,A_NONE,A_RORV + ); + TOpCG2AsmOpImm: array[topcg] of TAsmOp = ( + A_NONE,A_MOV,A_ADD,A_AND,A_UDIV,A_SDIV,A_MUL,A_MUL,A_NEG,A_MVN,A_ORR,A_ASR,A_LSL,A_LSR,A_SUB,A_EOR,A_NONE,A_ROR + ); + TOpCmp2AsmCond: array[topcmp] of TAsmCond = (C_NONE,C_EQ,C_GT, + C_LT,C_GE,C_LE,C_NE,C_LS,C_CC,C_CS,C_HI + ); + + +implementation + + uses + globals,verbose,systems,cutils, + paramgr,fmodule, + symtable,symsym, + tgobj, + procinfo,cpupi; + + + procedure tcgaarch64.make_simple_ref(list:TAsmList; var op: tasmop; size: tcgsize; oppostfix: toppostfix; var ref: treference; preferred_newbasereg: tregister); + var + href: treference; + so: tshifterop; + accesssize: longint; + begin + if (ref.base=NR_NO) then + begin + if ref.shiftmode<>SM_None then + internalerror(2014110701); + ref.base:=ref.index; + ref.index:=NR_NO; + end; + { no abitrary scale factor support (the generic code doesn't set it, + AArch-specific code shouldn't either) } + if not(ref.scalefactor in [0,1]) then + internalerror(2014111002); + + case simple_ref_type(op,size,oppostfix,ref) of + sr_simple: + exit; + sr_internal_illegal: + internalerror(2014121702); + sr_complex: + { continue } ; + end; + + if assigned(ref.symbol) then + begin + { internal "load symbol" instructions should already be valid } + if assigned(ref.symboldata) or + (ref.refaddr in [addr_pic,addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset]) then + internalerror(2014110802); + { no relative symbol support (needed) yet } + if assigned(ref.relsymbol) then + internalerror(2014111001); + { loading a symbol address (whether it's in the GOT or not) consists + of two parts: first load the page on which it is located, then + either the offset in the page or load the value at that offset in + the page. This final GOT-load can be relaxed by the linker in case + the variable itself can be stored directly in the GOT } + if (preferred_newbasereg=NR_NO) or + (ref.base=preferred_newbasereg) or + (ref.index=preferred_newbasereg) then + preferred_newbasereg:=getaddressregister(list); + { load the (GOT) page } + reference_reset_symbol(href,ref.symbol,0,8); + if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and + (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or + ((ref.symbol.typ=AT_DATA) and + (ref.symbol.bind=AB_LOCAL)) then + href.refaddr:=addr_page + else + href.refaddr:=addr_gotpage; + list.concat(taicpu.op_reg_ref(A_ADRP,preferred_newbasereg,href)); + { load the GOT entry (= address of the variable) } + reference_reset_base(href,preferred_newbasereg,0,sizeof(pint)); + href.symbol:=ref.symbol; + { code symbols defined in the current compilation unit do not + have to be accessed via the GOT } + if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and + (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or + ((ref.symbol.typ=AT_DATA) and + (ref.symbol.bind=AB_LOCAL)) then + begin + href.base:=NR_NO; + href.refaddr:=addr_pageoffset; + list.concat(taicpu.op_reg_reg_ref(A_ADD,preferred_newbasereg,preferred_newbasereg,href)); + end + else + begin + href.refaddr:=addr_gotpageoffset; + { use a_load_ref_reg() rather than directly encoding the LDR, + so that we'll check the validity of the reference } + a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,preferred_newbasereg); + end; + { set as new base register } + if ref.base=NR_NO then + ref.base:=preferred_newbasereg + else if ref.index=NR_NO then + ref.index:=preferred_newbasereg + else + begin + { make sure it's valid in case ref.base is SP -> make it + the second operand} + a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,preferred_newbasereg,ref.base,preferred_newbasereg); + ref.base:=preferred_newbasereg + end; + ref.symbol:=nil; + end; + + { base & index } + if (ref.base<>NR_NO) and + (ref.index<>NR_NO) then + begin + case op of + A_LDR, A_STR: + begin + if (ref.shiftmode=SM_None) and + (ref.shiftimm<>0) then + internalerror(2014110805); + { wrong shift? (possible in case of something like + array_of_2byte_rec[x].bytefield -> shift will be set 1, but + the final load is a 1 byte -> can't use shift after all } + if (ref.shiftmode in [SM_LSL,SM_UXTW,SM_SXTW]) and + ((ref.shiftimm<>BsfDWord(tcgsizep2size[size])) or + (ref.offset<>0)) then + begin + if preferred_newbasereg=NR_NO then + preferred_newbasereg:=getaddressregister(list); + { "add" supports a superset of the shift modes supported by + load/store instructions } + shifterop_reset(so); + so.shiftmode:=ref.shiftmode; + so.shiftimm:=ref.shiftimm; + list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,preferred_newbasereg,ref.base,ref.index,so)); + reference_reset_base(ref,preferred_newbasereg,ref.offset,ref.alignment); + { possibly still an invalid offset -> fall through } + end + else if ref.offset<>0 then + begin + if (preferred_newbasereg=NR_NO) or + { we keep ref.index, so it must not be overwritten } + (ref.index=preferred_newbasereg) then + preferred_newbasereg:=getaddressregister(list); + { add to the base and not to the index, because the index + may be scaled; this works even if the base is SP } + a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,preferred_newbasereg); + ref.offset:=0; + ref.base:=preferred_newbasereg; + { finished } + exit; + end + else + { valid -> exit } + exit; + end; + { todo } + A_LD1,A_LD2,A_LD3,A_LD4, + A_ST1,A_ST2,A_ST3,A_ST4: + internalerror(2014110704); + { these don't support base+index } + A_LDUR,A_STUR, + A_LDP,A_STP: + begin + { these either don't support pre-/post-indexing, or don't + support it with base+index } + if ref.addressmode<>AM_OFFSET then + internalerror(2014110911); + if preferred_newbasereg=NR_NO then + preferred_newbasereg:=getaddressregister(list); + if ref.shiftmode<>SM_None then + begin + { "add" supports a superset of the shift modes supported by + load/store instructions } + shifterop_reset(so); + so.shiftmode:=ref.shiftmode; + so.shiftimm:=ref.shiftimm; + list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,preferred_newbasereg,ref.base,ref.index,so)); + end + else + a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,ref.index,ref.base,preferred_newbasereg); + reference_reset_base(ref,preferred_newbasereg,ref.offset,ref.alignment); + { fall through to the handling of base + offset, since the + offset may still be too big } + end; + else + internalerror(2014110901); + end; + end; + + { base + offset } + if ref.base<>NR_NO then + begin + { valid offset for LDUR/STUR -> use that } + if (ref.addressmode=AM_OFFSET) and + (op in [A_LDR,A_STR]) and + (ref.offset>=-256) and + (ref.offset<=255) then + begin + if op=A_LDR then + op:=A_LDUR + else + op:=A_STUR + end + { if it's not a valid LDUR/STUR, use LDR/STR } + else if (op in [A_LDUR,A_STUR]) and + ((ref.offset<-256) or + (ref.offset>255) or + (ref.addressmode<>AM_OFFSET)) then + begin + if op=A_LDUR then + op:=A_LDR + else + op:=A_STR + end; + case op of + A_LDR,A_STR: + begin + case ref.addressmode of + AM_PREINDEXED: + begin + { since the loaded/stored register cannot be the same + as the base register, we can safely add the + offset to the base if it doesn't fit} + if (ref.offset<-256) or + (ref.offset>255) then + begin + a_op_const_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base); + ref.offset:=0; + end; + end; + AM_POSTINDEXED: + begin + { cannot emulate post-indexing if we have to fold the + offset into the base register } + if (ref.offset<-256) or + (ref.offset>255) then + internalerror(2014110909); + { ok } + end; + AM_OFFSET: + begin + { unsupported offset -> fold into base register } + accesssize:=1 shl tcgsizep2size[size]; + if (ref.offset<0) or + (ref.offset>(((1 shl 12)-1)*accesssize)) or + ((ref.offset mod accesssize)<>0) then + begin + if preferred_newbasereg=NR_NO then + preferred_newbasereg:=getaddressregister(list); + { can we split the offset beween an + "add/sub (imm12 shl 12)" and the load (also an + imm12)? + -- the offset from the load will always be added, + that's why the lower bound has a smaller range + than the upper bound; it must also be a multiple + of the access size } + if (ref.offset>=-(((1 shl 12)-1) shl 12)) and + (ref.offset<=((1 shl 12)-1) shl 12 + ((1 shl 12)-1)) and + ((ref.offset mod accesssize)=0) then + begin + a_op_const_reg_reg(list,OP_ADD,OS_ADDR,(ref.offset shr 12) shl 12,ref.base,preferred_newbasereg); + ref.offset:=ref.offset-(ref.offset shr 12) shl 12; + end + else + begin + a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,preferred_newbasereg); + ref.offset:=0; + end; + reference_reset_base(ref,preferred_newbasereg,ref.offset,ref.alignment); + end; + end + else + internalerror(2014110904); + end; + end; + A_LDP,A_STP: + begin + { unsupported offset -> fold into base register (these + instructions support all addressmodes) } + if (ref.offset<-(1 shl (6+tcgsizep2size[size]))) or + (ref.offset>(1 shl (6+tcgsizep2size[size]))-1) then + begin + case ref.addressmode of + AM_POSTINDEXED: + { don't emulate post-indexing if we have to fold the + offset into the base register } + internalerror(2014110910); + AM_PREINDEXED: + { this means the offset must be added to the current + base register } + preferred_newbasereg:=ref.base; + AM_OFFSET: + if preferred_newbasereg=NR_NO then + preferred_newbasereg:=getaddressregister(list); + end; + a_op_const_reg_reg(list,OP_ADD,OS_ADDR,ref.offset,ref.base,preferred_newbasereg); + reference_reset_base(ref,preferred_newbasereg,0,ref.alignment); + end + end; + A_LDUR,A_STUR: + begin + { valid, checked above } + end; + { todo } + A_LD1,A_LD2,A_LD3,A_LD4, + A_ST1,A_ST2,A_ST3,A_ST4: + internalerror(2014110908); + else + internalerror(2014110708); + end; + { done } + exit; + end; + + { only an offset -> change to base (+ offset 0) } + if preferred_newbasereg=NR_NO then + preferred_newbasereg:=getaddressregister(list); + a_load_const_reg(list,OS_ADDR,ref.offset,preferred_newbasereg); + reference_reset_base(ref,preferred_newbasereg,0,newalignment(8,ref.offset)); + end; + + + function tcgaarch64.makeregsize(reg: tregister; size: tcgsize): tregister; + var + subreg:Tsubregister; + begin + subreg:=cgsize2subreg(getregtype(reg),size); + result:=reg; + setsubreg(result,subreg); + end; + + + function tcgaarch64.getfpuregister(list: TAsmList; size: Tcgsize): Tregister; + begin + internalerror(2014122110); + { squash warning } + result:=NR_NO; + end; + + + function tcgaarch64.handle_load_store(list: TAsmList; op: tasmop; size: tcgsize; oppostfix: toppostfix; reg: tregister; ref: treference):treference; + begin + make_simple_ref(list,op,size,oppostfix,ref,NR_NO); + list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),oppostfix)); + result:=ref; + end; + + + procedure tcgaarch64.handle_reg_imm12_reg(list: TAsmList; op: Tasmop; size: tcgsize; src: tregister; a: tcgint; dst: tregister; tmpreg: tregister; setflags, usedest: boolean); + var + instr: taicpu; + so: tshifterop; + hadtmpreg: boolean; + begin + { imm12 } + if (a>=0) and + (a<=((1 shl 12)-1)) then + if usedest then + instr:=taicpu.op_reg_reg_const(op,dst,src,a) + else + instr:=taicpu.op_reg_const(op,src,a) + { imm12 lsl 12 } + else if (a and not(((tcgint(1) shl 12)-1) shl 12))=0 then + begin + so.shiftmode:=SM_LSL; + so.shiftimm:=12; + if usedest then + instr:=taicpu.op_reg_reg_const_shifterop(op,dst,src,a shr 12,so) + else + instr:=taicpu.op_reg_const_shifterop(op,src,a shr 12,so) + end + else + begin + { todo: other possible optimizations (e.g. load 16 bit constant in + register and then add/sub/cmp/cmn shifted the rest) } + if tmpreg=NR_NO then + begin + hadtmpreg:=false; + tmpreg:=getintregister(list,size); + end + else + begin + hadtmpreg:=true; + getcpuregister(list,tmpreg); + end; + a_load_const_reg(list,size,a,tmpreg); + if usedest then + instr:=taicpu.op_reg_reg_reg(op,dst,src,tmpreg) + else + instr:=taicpu.op_reg_reg(op,src,tmpreg); + if hadtmpreg then + ungetcpuregister(list,tmpreg); + end; + if setflags then + setoppostfix(instr,PF_S); + list.concat(instr); + end; + + +{**************************************************************************** + Assembler code +****************************************************************************} + + procedure tcgaarch64.init_register_allocators; + begin + inherited init_register_allocators; + + rg[R_INTREGISTER]:=trgintcpu.create(R_INTREGISTER,R_SUBWHOLE, + [RS_X0,RS_X1,RS_X2,RS_X3,RS_X4,RS_X5,RS_X6,RS_X7,RS_X8, + RS_X9,RS_X10,RS_X11,RS_X12,RS_X13,RS_X14,RS_X15,RS_X16,RS_X17, + RS_X19,RS_X20,RS_X21,RS_X22,RS_X23,RS_X24,RS_X25,RS_X26,RS_X27,RS_X28 + { maybe we can enable this in the future for leaf functions (it's + the frame pointer) + ,RS_X29 }], + first_int_imreg,[]); + + rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBMMD, + [RS_Q0,RS_Q1,RS_Q2,RS_Q3,RS_Q4,RS_Q5,RS_Q6,RS_Q7, + RS_Q8,RS_Q9,RS_Q10,RS_Q11,RS_Q12,RS_Q13,RS_Q14,RS_Q15, + RS_Q16,RS_Q17,RS_Q18,RS_Q19,RS_Q20,RS_Q21,RS_Q22,RS_Q23, + RS_Q24,RS_Q25,RS_Q26,RS_Q27,RS_Q28,RS_Q29,RS_Q30,RS_Q31], + first_mm_imreg,[]); + end; + + + procedure tcgaarch64.done_register_allocators; + begin + rg[R_INTREGISTER].free; + rg[R_FPUREGISTER].free; + rg[R_MMREGISTER].free; + inherited done_register_allocators; + end; + + + function tcgaarch64.getmmregister(list: TAsmList; size: tcgsize):tregister; + begin + case size of + OS_F32: + result:=rg[R_MMREGISTER].getregister(list,R_SUBMMS); + OS_F64: + result:=rg[R_MMREGISTER].getregister(list,R_SUBMMD) + else + internalerror(2014102701); + end; + end; + + + procedure tcgaarch64.a_call_name(list: TAsmList; const s: string; weak: boolean); + begin + if not weak then + list.concat(taicpu.op_sym(A_BL,current_asmdata.RefAsmSymbol(s))) + else + list.concat(taicpu.op_sym(A_BL,current_asmdata.WeakRefAsmSymbol(s))); + end; + + + procedure tcgaarch64.a_call_reg(list:TAsmList;Reg:tregister); + begin + list.concat(taicpu.op_reg(A_BLR,reg)); + end; + + + {********************** load instructions ********************} + + procedure tcgaarch64.a_load_const_reg(list: TAsmList; size: tcgsize; a: tcgint; reg : tregister); + var + preva: tcgint; + opc: tasmop; + shift,maxshift: byte; + so: tshifterop; + reginited: boolean; + mask: tcgint; + begin + { if we load a value into a 32 bit register, it is automatically + zero-extended to 64 bit } + if (high(a)=0) and + (size in [OS_64,OS_S64]) then + begin + size:=OS_32; + reg:=makeregsize(reg,size); + end; + { values <= 32 bit are stored in a 32 bit register } + if not(size in [OS_64,OS_S64]) then + a:=cardinal(a); + + if size in [OS_64,OS_S64] then + begin + mask:=-1; + maxshift:=64; + end + else + begin + mask:=$ffffffff; + maxshift:=32; + end; + { single movn enough? (to be extended) } + shift:=16; + preva:=a; + repeat + if (a shr shift)=(mask shr shift) then + begin + if shift=16 then + list.concat(taicpu.op_reg_const(A_MOVN,reg,not(word(preva)))) + else + begin + shifterop_reset(so); + so.shiftmode:=SM_LSL; + so.shiftimm:=shift-16; + list.concat(taicpu.op_reg_const_shifterop(A_MOVN,reg,not(word(preva)),so)); + end; + exit; + end; + { only try the next 16 bits if the current one is all 1 bits, since + the movn will set all lower bits to 1 } + if word(a shr (shift-16))<>$ffff then + break; + inc(shift,16); + until shift=maxshift; + reginited:=false; + shift:=0; + { can be optimized later to use more movn } + repeat + { leftover is shifterconst? (don't check if we can represent it just + as effectively with movz/movk, as this check is expensive) } + if ((shift0) and + ((a shr 16)<>0)) and + is_shifter_const(a shl shift,size) then + begin + if reginited then + list.concat(taicpu.op_reg_reg_const(A_ORR,reg,reg,a shl shift)) + else + list.concat(taicpu.op_reg_reg_const(A_ORR,reg,makeregsize(NR_XZR,size),a shl shift)); + exit; + end; + { set all 16 bit parts <> 0 } + if (word(a)<>0) or + ((shift=0) and + (a=0)) then + if shift=0 then + begin + list.concat(taicpu.op_reg_const(A_MOVZ,reg,word(a))); + reginited:=true; + end + else + begin + shifterop_reset(so); + so.shiftmode:=SM_LSL; + so.shiftimm:=shift; + if not reginited then + begin + opc:=A_MOVZ; + reginited:=true; + end + else + opc:=A_MOVK; + list.concat(taicpu.op_reg_const_shifterop(opc,reg,word(a),so)); + end; + preva:=a; + a:=a shr 16; + inc(shift,16); + until word(preva)=preva; + if not reginited then + internalerror(2014102702); + end; + + + procedure tcgaarch64.a_load_const_ref(list: TAsmList; size: tcgsize; a: tcgint; const ref: treference); + var + reg: tregister; + begin + { use the zero register if possible } + if a=0 then + begin + if size in [OS_64,OS_S64] then + reg:=NR_XZR + else + reg:=NR_WZR; + a_load_reg_ref(list,size,size,reg,ref); + end + else + inherited; + end; + + + procedure tcgaarch64.a_load_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); + var + oppostfix:toppostfix; + hreg: tregister; + begin + if tcgsize2Size[fromsize]>=tcgsize2Size[tosize] then + fromsize:=tosize + { have a 32 bit register but need a 64 bit one? } + else if tosize in [OS_64,OS_S64] then + begin + { sign extend if necessary } + if fromsize in [OS_S8,OS_S16,OS_S32] then + begin + { can't overwrite reg, may be a constant reg } + hreg:=getintregister(list,tosize); + a_load_reg_reg(list,fromsize,tosize,reg,hreg); + reg:=hreg; + end + else + { top 32 bit are zero by default } + reg:=makeregsize(reg,OS_64); + fromsize:=tosize; + end; + if (ref.alignment<>0) and + (ref.alignment=tcgsize2Size[tosize] then + fromsize:=tosize; + { ensure that all bits of the 32/64 register are always correctly set: + * default behaviour is always to zero-extend to the entire (64 bit) + register -> unsigned 8/16/32 bit loads only exist with a 32 bit + target register, as the upper 32 bit will be zeroed implicitly + -> always make target register 32 bit + * signed loads exist both with 32 and 64 bit target registers, + depending on whether the value should be sign extended to 32 or + to 64 bit (if sign extended to 32 bit, the upper 32 bits of the + corresponding 64 bit register are again zeroed) -> no need to + change anything (we only have 32 and 64 bit registers), except that + when loading an OS_S32 to a 32 bit register, we don't need/can't + use sign extension + } + if fromsize in [OS_8,OS_16,OS_32] then + reg:=makeregsize(reg,OS_32); + if (ref.alignment<>0) and + (ref.alignment insert conversion when when + we have to truncate/sign extend inside the (32 or 64 bit) register + holding the value, and when we sign extend from a 32 to a 64 bit + register } + if (tcgsize2size[fromsize]>tcgsize2size[tosize]) or + ((tcgsize2size[fromsize]=tcgsize2size[tosize]) and + (fromsize<>tosize) and + not(fromsize in [OS_32,OS_S32,OS_64,OS_S64])) or + ((fromsize in [OS_S8,OS_S16,OS_S32]) and + (tosize in [OS_64,OS_S64])) or + { needs to mask out the sign in the top 16 bits } + ((fromsize=OS_S8) and + (tosize=OS_16)) then + begin + case tosize of + OS_8: + list.concat(setoppostfix(taicpu.op_reg_reg(A_UXT,reg2,makeregsize(reg1,OS_32)),PF_B)); + OS_16: + list.concat(setoppostfix(taicpu.op_reg_reg(A_UXT,reg2,makeregsize(reg1,OS_32)),PF_H)); + OS_S8: + list.concat(setoppostfix(taicpu.op_reg_reg(A_SXT,reg2,makeregsize(reg1,OS_32)),PF_B)); + OS_S16: + list.concat(setoppostfix(taicpu.op_reg_reg(A_SXT,reg2,makeregsize(reg1,OS_32)),PF_H)); + { while "mov wN, wM" automatically inserts a zero-extension and + hence we could encode a 64->32 bit move like that, the problem + is that we then can't distinguish 64->32 from 32->32 moves, and + the 64->32 truncation could be removed altogether... So use a + different instruction } + OS_32, + OS_S32: + { in theory, reg1 should be 64 bit here (since fromsize>tosize), + but because of the way location_force_register() tries to + avoid superfluous zero/sign extensions, it's not always the + case -> also force reg1 to to 64 bit } + list.concat(taicpu.op_reg_reg_const_const(A_UBFIZ,makeregsize(reg2,OS_64),makeregsize(reg1,OS_64),0,32)); + OS_64, + OS_S64: + list.concat(setoppostfix(taicpu.op_reg_reg(A_SXT,reg2,makeregsize(reg1,OS_32)),PF_W)); + else + internalerror(2002090901); + end; + end + else + begin + { 32 -> 32 bit move implies zero extension (sign extensions have + been handled above) -> also use for 32 <-> 64 bit moves } + if not(fromsize in [OS_64,OS_S64]) or + not(tosize in [OS_64,OS_S64]) then + instr:=taicpu.op_reg_reg(A_MOV,makeregsize(reg2,OS_32),makeregsize(reg1,OS_32)) + else + instr:=taicpu.op_reg_reg(A_MOV,reg2,reg1); + list.Concat(instr); + { Notify the register allocator that we have written a move instruction so + it can try to eliminate it. } + add_move_instruction(instr); + end; + end; + + + procedure tcgaarch64.a_loadaddr_ref_reg(list: TAsmList; const ref: treference; r: tregister); + var + href: treference; + so: tshifterop; + op: tasmop; + begin + op:=A_LDR; + href:=ref; + { simplify as if we're going to perform a regular 64 bit load, using + "r" as the new base register if possible/necessary } + make_simple_ref(list,op,OS_ADDR,PF_None,href,r); + { load literal? } + if assigned(href.symbol) then + begin + if (href.base<>NR_NO) or + (href.index<>NR_NO) or + not assigned(href.symboldata) then + internalerror(2014110912); + list.concat(taicpu.op_reg_sym_ofs(A_ADR,r,href.symbol,href.offset)); + end + else + begin + if href.index<>NR_NO then + begin + if href.shiftmode<>SM_None then + begin + { "add" supports a supperset of the shift modes supported by + load/store instructions } + shifterop_reset(so); + so.shiftmode:=href.shiftmode; + so.shiftimm:=href.shiftimm; + list.concat(taicpu.op_reg_reg_reg_shifterop(A_ADD,r,href.base,href.index,so)); + end + else + a_op_reg_reg_reg(list,OP_ADD,OS_ADDR,href.index,href.base,r); + end + else if href.offset<>0 then + a_op_const_reg_reg(list,OP_ADD,OS_ADDR,href.offset,href.base,r) + else + a_load_reg_reg(list,OS_ADDR,OS_ADDR,href.base,r); + end; + end; + + + procedure tcgaarch64.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); + begin + internalerror(2014122107) + end; + + + procedure tcgaarch64.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister); + begin + internalerror(2014122108) + end; + + + procedure tcgaarch64.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference); + begin + internalerror(2014122109) + end; + + + procedure tcgaarch64.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister; shuffle: pmmshuffle); + var + instr: taicpu; + begin + if assigned(shuffle) and + not shufflescalar(shuffle) then + internalerror(2014122104); + if fromsize=tosize then + begin + instr:=taicpu.op_reg_reg(A_FMOV,reg2,reg1); + { Notify the register allocator that we have written a move + instruction so it can try to eliminate it. } + add_move_instruction(instr); + end + else + begin + if (reg_cgsize(reg1)<>fromsize) or + (reg_cgsize(reg2)<>tosize) then + internalerror(2014110913); + instr:=taicpu.op_reg_reg(A_FCVT,reg2,reg1); + end; + list.Concat(instr); + end; + + + procedure tcgaarch64.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle); + var + tmpreg: tregister; + begin + if assigned(shuffle) and + not shufflescalar(shuffle) then + internalerror(2014122105); + tmpreg:=NR_NO; + if (fromsize<>tosize) then + begin + tmpreg:=reg; + reg:=getmmregister(list,fromsize); + end; + handle_load_store(list,A_LDR,fromsize,PF_None,reg,ref); + if (fromsize<>tosize) then + a_loadmm_reg_reg(list,fromsize,tosize,reg,tmpreg,nil); + end; + + + procedure tcgaarch64.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle); + var + tmpreg: tregister; + begin + if assigned(shuffle) and + not shufflescalar(shuffle) then + internalerror(2014122106); + if (fromsize<>tosize) then + begin + tmpreg:=getmmregister(list,tosize); + a_loadmm_reg_reg(list,fromsize,tosize,reg,tmpreg,nil); + reg:=tmpreg; + end; + handle_load_store(list,A_STR,tosize,PF_NONE,reg,ref); + end; + + + procedure tcgaarch64.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tcgsize; intreg, mmreg: tregister; shuffle: pmmshuffle); + begin + if not shufflescalar(shuffle) then + internalerror(2014122801); + if not(tcgsize2size[fromsize] in [4,8]) or + (tcgsize2size[fromsize]<>tcgsize2size[tosize]) then + internalerror(2014122803); + list.concat(taicpu.op_reg_reg(A_INS,mmreg,intreg)); + end; + + + procedure tcgaarch64.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tcgsize; mmreg, intreg: tregister; shuffle: pmmshuffle); + begin + if not shufflescalar(shuffle) then + internalerror(2014122802); + if not(tcgsize2size[fromsize] in [4,8]) or + (tcgsize2size[fromsize]<>tcgsize2size[tosize]) then + internalerror(2014122804); + list.concat(taicpu.op_reg_reg(A_UMOV,intreg,mmreg)); + end; + + + procedure tcgaarch64.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tcgsize; src, dst: tregister; shuffle: pmmshuffle); + begin + case op of + { "xor Vx,Vx" is used to initialize global regvars to 0 } + OP_XOR: + begin + if (src<>dst) or + (reg_cgsize(src)<>size) or + assigned(shuffle) then + internalerror(2015011401); + case size of + OS_F32, + OS_F64: + list.concat(taicpu.op_reg_const(A_MOVI,makeregsize(dst,OS_F64),0)); + else + internalerror(2015011402); + end; + end + else + internalerror(2015011403); + end; + end; + + + procedure tcgaarch64.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); + var + bitsize, + signbit: longint; + begin + if srcsize in [OS_64,OS_S64] then + begin + bitsize:=64; + signbit:=6; + end + else + begin + bitsize:=32; + signbit:=5; + end; + { source is 0 -> dst will have to become 255 } + list.concat(taicpu.op_reg_const(A_CMP,src,0)); + if reverse then + begin + list.Concat(taicpu.op_reg_reg(A_CLZ,makeregsize(dst,srcsize),src)); + { xor 31/63 is the same as setting the lower 5/6 bits to + "31/63-(lower 5/6 bits of dst)" } + list.Concat(taicpu.op_reg_reg_const(A_EOR,dst,dst,bitsize-1)); + end + else + begin + list.Concat(taicpu.op_reg_reg(A_RBIT,makeregsize(dst,srcsize),src)); + list.Concat(taicpu.op_reg_reg(A_CLZ,dst,dst)); + end; + { set dst to -1 if src was 0 } + list.Concat(taicpu.op_reg_reg_reg_cond(A_CSINV,dst,dst,makeregsize(NR_XZR,dstsize),C_NE)); + { mask the -1 to 255 if src was 0 (anyone find a two-instruction + branch-free version? All of mine are 3...) } + list.Concat(setoppostfix(taicpu.op_reg_reg(A_UXT,makeregsize(dst,OS_32),makeregsize(dst,OS_32)),PF_B)); + end; + + + procedure tcgaarch64.a_load_reg_ref_unaligned(list: TAsmList; fromsize, tosize: tcgsize; register: tregister; const ref: treference); + var + href: treference; + hreg1, hreg2, tmpreg: tregister; + begin + if fromsize in [OS_64,OS_S64] then + begin + { split into two 32 bit stores } + hreg1:=makeregsize(register,OS_32); + hreg2:=getintregister(list,OS_32); + a_op_const_reg_reg(list,OP_SHR,OS_64,32,register,makeregsize(hreg2,OS_64)); + if target_info.endian=endian_big then + begin + tmpreg:=hreg1; + hreg1:=hreg2; + hreg2:=tmpreg; + end; + { can we use STP? } + if (ref.alignment=4) and + (simple_ref_type(A_STP,OS_32,PF_None,ref)=sr_simple) then + list.concat(taicpu.op_reg_reg_ref(A_STP,hreg1,hreg2,ref)) + else + begin + a_load_reg_ref(list,OS_32,OS_32,hreg1,ref); + href:=ref; + inc(href.offset,4); + a_load_reg_ref(list,OS_32,OS_32,hreg2,href); + end; + end + else + inherited; + end; + + + procedure tcgaarch64.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]) then + a_load_reg_reg(list,OS_32,size,makeregsize(dst,OS_32),makeregsize(dst,OS_32)) + end; + + + procedure tcgaarch64.a_op_const_reg(list: TAsmList; op: topcg; size: tcgsize; a: tcgint; reg: tregister); + begin + optimize_op_const(size,op,a); + case op of + OP_NONE: + exit; + OP_MOVE: + a_load_const_reg(list,size,a,reg); + OP_NEG,OP_NOT: + internalerror(200306011); + else + a_op_const_reg_reg(list,op,size,a,reg,reg); + end; + end; + + + procedure tcgaarch64.a_op_reg_reg(list:TAsmList;op:topcg;size:tcgsize;src,dst:tregister); + begin + Case op of + OP_NEG, + OP_NOT: + begin + list.concat(taicpu.op_reg_reg(TOpCG2AsmOpReg[op],dst,src)); + maybeadjustresult(list,op,size,dst); + end + else + a_op_reg_reg_reg(list,op,size,src,dst,dst); + end; + end; + + + procedure tcgaarch64.a_op_const_reg_reg(list: TAsmList; op: topcg; size: tcgsize; a: tcgint; src, dst: tregister); + var + l: tlocation; + begin + a_op_const_reg_reg_checkoverflow(list,op,size,a,src,dst,false,l); + end; + + + procedure tcgaarch64.a_op_reg_reg_reg(list: TAsmList; op: topcg; size: tcgsize; src1, src2, dst: tregister); + var + hreg: tregister; + begin + { no ROLV opcode... } + if op=OP_ROL then + begin + case size of + OS_32,OS_S32, + OS_64,OS_S64: + begin + hreg:=getintregister(list,size); + a_load_const_reg(list,size,tcgsize2size[size]*8,hreg); + a_op_reg_reg(list,OP_SUB,size,src1,hreg); + a_op_reg_reg_reg(list,OP_ROR,size,hreg,src2,dst); + exit; + end; + else + internalerror(2014111005); + end; + end + else if (op=OP_ROR) and + not(size in [OS_32,OS_S32,OS_64,OS_S64]) then + internalerror(2014111006); + if TOpCG2AsmOpReg[op]=A_NONE then + internalerror(2014111007); + list.concat(taicpu.op_reg_reg_reg(TOpCG2AsmOpReg[op],dst,src2,src1)); + maybeadjustresult(list,op,size,dst); + end; + + + procedure tcgaarch64.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: topcg; size: tcgsize; a: tcgint; src, dst: tregister; setflags : boolean; var ovloc : tlocation); + var + shiftcountmask: longint; + constreg: tregister; + begin + { add/sub instructions have only positive immediate operands } + if (op in [OP_ADD,OP_SUB]) and + (a<0) then + begin + if op=OP_ADD then + op:=op_SUB + else + op:=OP_ADD; + { avoid range/overflow error in case a = low(tcgint) } +{$push}{$r-}{$q-} + a:=-a; +{$pop} + end; + ovloc.loc:=LOC_VOID; + optimize_op_const(size,op,a); + case op of + OP_NONE: + begin + a_load_reg_reg(list,size,size,src,dst); + exit; + end; + OP_MOVE: + begin + a_load_const_reg(list,size,a,dst); + exit; + end; + end; + case op of + OP_ADD, + OP_SUB: + begin + handle_reg_imm12_reg(list,TOpCG2AsmOpImm[op],size,src,a,dst,NR_NO,setflags,true); + { on a 64 bit target, overflows with smaller data types + are handled via range errors } + if setflags and + (size in [OS_64,OS_S64]) then + begin + location_reset(ovloc,LOC_FLAGS,OS_8); + if size=OS_64 then + if op=OP_ADD then + ovloc.resflags:=F_CS + else + ovloc.resflags:=F_CC + else + ovloc.resflags:=F_VS; + end; + end; + OP_OR, + OP_AND, + OP_XOR: + begin + if not(size in [OS_64,OS_S64]) then + a:=cardinal(a); + if is_shifter_const(a,size) then + list.concat(taicpu.op_reg_reg_const(TOpCG2AsmOpReg[op],dst,src,a)) + else + begin + constreg:=getintregister(list,size); + a_load_const_reg(list,size,a,constreg); + a_op_reg_reg_reg(list,op,size,constreg,src,dst); + end; + end; + OP_SHL, + OP_SHR, + OP_SAR: + begin + if size in [OS_64,OS_S64] then + shiftcountmask:=63 + else + shiftcountmask:=31; + if (a and shiftcountmask)<>0 Then + list.concat(taicpu.op_reg_reg_const( + TOpCG2AsmOpImm[Op],dst,src,a and shiftcountmask)) + else + a_load_reg_reg(list,size,size,src,dst); + if (a and not(tcgint(shiftcountmask)))<>0 then + internalError(2014112101); + end; + OP_ROL, + OP_ROR: + begin + case size of + OS_32,OS_S32: + if (a and not(tcgint(31)))<>0 then + internalError(2014112102); + OS_64,OS_S64: + if (a and not(tcgint(63)))<>0 then + internalError(2014112103); + else + internalError(2014112104); + end; + { there's only a ror opcode } + if op=OP_ROL then + a:=(tcgsize2size[size]*8)-a; + list.concat(taicpu.op_reg_reg_const(A_ROR,dst,src,a)); + end; + OP_MUL, + OP_IMUL, + OP_DIV, + OP_IDIV: + begin + constreg:=getintregister(list,size); + a_load_const_reg(list,size,a,constreg); + a_op_reg_reg_reg_checkoverflow(list,op,size,constreg,src,dst,setflags,ovloc); + end; + else + internalerror(2014111403); + end; + maybeadjustresult(list,op,size,dst); + end; + + + procedure tcgaarch64.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: topcg; size: tcgsize; src1, src2, dst: tregister; setflags : boolean; var ovloc : tlocation); + var + tmpreg1: tregister; + begin + ovloc.loc:=LOC_VOID; + { overflow can only occur with 64 bit calculations on 64 bit cpus } + if setflags and + (size in [OS_64,OS_S64]) then + begin + case op of + OP_ADD, + OP_SUB: + begin + list.concat(setoppostfix(taicpu.op_reg_reg_reg(TOpCG2AsmOpReg[op],dst,src2,src1),PF_S)); + ovloc.loc:=LOC_FLAGS; + if size=OS_64 then + if op=OP_ADD then + ovloc.resflags:=F_CS + else + ovloc.resflags:=F_CC + else + ovloc.resflags:=F_VS; + { finished; since we won't call through to a_op_reg_reg_reg, + adjust the result here if necessary } + maybeadjustresult(list,op,size,dst); + exit; + end; + OP_MUL: + begin + { check whether the upper 64 bit of the 128 bit product is 0 } + tmpreg1:=getintregister(list,OS_64); + list.concat(taicpu.op_reg_reg_reg(A_UMULH,tmpreg1,src2,src1)); + list.concat(taicpu.op_reg_const(A_CMP,tmpreg1,0)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + { still have to perform the actual multiplication } + end; + OP_IMUL: + begin + { check whether the sign bit of the (128 bit) result is the + same as "sign bit of src1" xor "signbit of src2" (if so, no + overflow and the xor-product of all sign bits is 0) } + tmpreg1:=getintregister(list,OS_64); + list.concat(taicpu.op_reg_reg_reg(A_SMULH,tmpreg1,src2,src1)); + list.concat(taicpu.op_reg_reg_reg(A_EOR,tmpreg1,tmpreg1,src1)); + list.concat(taicpu.op_reg_reg_reg(A_EOR,tmpreg1,tmpreg1,src2)); + list.concat(taicpu.op_reg_const(A_TST,tmpreg1,$80000000)); + ovloc.loc:=LOC_FLAGS; + ovloc.resflags:=F_NE; + { still have to perform the actual multiplication } + end; + OP_IDIV, + OP_DIV: + begin + { not handled here, needs div-by-zero check (dividing by zero + just gives a 0 result on aarch64), and low(int64) div -1 + check for overflow) } + internalerror(2014122101); + end; + end; + end; + a_op_reg_reg_reg(list,op,size,src1,src2,dst); + end; + + + + {*************** compare instructructions ****************} + + procedure tcgaarch64.a_cmp_const_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); + var + op: tasmop; + begin + if a>=0 then + op:=A_CMP + else + op:=A_CMN; + { avoid range/overflow error in case a=low(tcgint) } +{$push}{$r-}{$q-} + handle_reg_imm12_reg(list,op,size,reg,abs(a),NR_XZR,NR_NO,false,false); +{$pop} + a_jmp_cond(list,cmp_op,l); + end; + + + procedure tcgaarch64.a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1,reg2: tregister; l: tasmlabel); + begin + list.concat(taicpu.op_reg_reg(A_CMP,reg2,reg1)); + a_jmp_cond(list,cmp_op,l); + end; + + + procedure tcgaarch64.a_jmp_always(list: TAsmList; l: TAsmLabel); + var + ai: taicpu; + begin + ai:=TAiCpu.op_sym(A_B,current_asmdata.RefAsmSymbol(l.name)); + ai.is_jmp:=true; + list.Concat(ai); + end; + + + procedure tcgaarch64.a_jmp_name(list: TAsmList; const s: string); + var + ai: taicpu; + begin + ai:=TAiCpu.op_sym(A_B,current_asmdata.RefAsmSymbol(s)); + ai.is_jmp:=true; + list.Concat(ai); + end; + + + procedure tcgaarch64.a_jmp_cond(list: TAsmList; cond: TOpCmp; l: TAsmLabel); + var + ai: taicpu; + begin + ai:=TAiCpu.op_sym(A_B,l); + ai.is_jmp:=true; + ai.SetCondition(TOpCmp2AsmCond[cond]); + list.Concat(ai); + end; + + + procedure tcgaarch64.a_jmp_flags(list: TAsmList; const f: tresflags; l: tasmlabel); + var + ai : taicpu; + begin + ai:=Taicpu.op_sym(A_B,l); + ai.is_jmp:=true; + ai.SetCondition(flags_to_cond(f)); + list.Concat(ai); + end; + + + procedure tcgaarch64.g_flags2reg(list: TAsmList; size: tcgsize; const f: tresflags; reg: tregister); + begin + list.concat(taicpu.op_reg_cond(A_CSET,reg,flags_to_cond(f))); + end; + + + procedure tcgaarch64.g_overflowcheck(list: TAsmList; const loc: tlocation; def: tdef); + begin + { we need an explicit overflow location, because there are many + possibilities (not just the overflow flag, which is only used for + signed add/sub) } + internalerror(2014112303); + end; + + + procedure tcgaarch64.g_overflowcheck_loc(list: TAsmList; const loc: tlocation; def: tdef; ovloc : tlocation); + var + hl : tasmlabel; + hflags : tresflags; + begin + if not(cs_check_overflow in current_settings.localswitches) then + exit; + current_asmdata.getjumplabel(hl); + case ovloc.loc of + LOC_FLAGS: + begin + hflags:=ovloc.resflags; + inverse_flags(hflags); + cg.a_jmp_flags(list,hflags,hl); + end; + else + internalerror(2014112304); + end; + a_call_name(list,'FPC_OVERFLOW',false); + a_label(list,hl); + end; + + { *********** entry/exit code and address loading ************ } + + function tcgaarch64.save_regs(list: TAsmList; rt: tregistertype; lowsr, highsr: tsuperregister; sub: tsubregister): longint; + var + ref: treference; + sr: tsuperregister; + pairreg: tregister; + begin + result:=0; + reference_reset_base(ref,NR_SP,-16,16); + ref.addressmode:=AM_PREINDEXED; + pairreg:=NR_NO; + { store all used registers pairwise } + for sr:=lowsr to highsr do + if sr in rg[rt].used_in_proc then + if pairreg=NR_NO then + pairreg:=newreg(rt,sr,sub) + else + begin + inc(result,16); + list.concat(taicpu.op_reg_reg_ref(A_STP,pairreg,newreg(rt,sr,sub),ref)); + pairreg:=NR_NO + end; + { one left -> store twice (stack must be 16 bytes aligned) } + if pairreg<>NR_NO then + begin + list.concat(taicpu.op_reg_reg_ref(A_STP,pairreg,pairreg,ref)); + inc(result,16); + end; + end; + + + procedure FixupOffsets(p:TObject;arg:pointer); + var + sym: tabstractnormalvarsym absolute p; + begin + if (tsym(p).typ in [paravarsym,localvarsym]) and + (sym.localloc.loc=LOC_REFERENCE) and + (sym.localloc.reference.base=NR_STACK_POINTER_REG) then + begin + sym.localloc.reference.base:=NR_FRAME_POINTER_REG; + dec(sym.localloc.reference.offset,PLongint(arg)^); + end; + end; + + + procedure tcgaarch64.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean); + var + ref: treference; + totalstackframesize: longint; + begin + if nostackframe then + exit; + { stack pointer has to be aligned to 16 bytes at all times } + localsize:=align(localsize,16); + + { save stack pointer and return address } + reference_reset_base(ref,NR_SP,-16,16); + ref.addressmode:=AM_PREINDEXED; + list.concat(taicpu.op_reg_reg_ref(A_STP,NR_FP,NR_LR,ref)); + { initialise frame pointer } + a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_SP,NR_FP); + + totalstackframesize:=localsize; + { save modified integer registers } + inc(totalstackframesize, + save_regs(list,R_INTREGISTER,RS_X19,RS_X28,R_SUBWHOLE)); + { only the lower 64 bits of the modified vector registers need to be + saved; if the caller needs the upper 64 bits, it has to save them + itself } + inc(totalstackframesize, + save_regs(list,R_MMREGISTER,RS_D8,RS_D15,R_SUBMMD)); + + { allocate stack space } + if localsize<>0 then + begin + localsize:=align(localsize,16); + current_procinfo.final_localsize:=localsize; + handle_reg_imm12_reg(list,A_SUB,OS_ADDR,NR_SP,localsize,NR_SP,NR_IP0,false,true); + end; + { By default, we use the frame pointer to access parameters passed via + the stack and the stack pointer to address local variables and temps + because + a) we can use bigger positive than negative offsets (so accessing + locals via negative offsets from the frame pointer would be less + efficient) + b) we don't know the local size while generating the code, so + accessing the parameters via the stack pointer is not possible + without copying them + The problem with this is the get_frame() intrinsic: + a) it must return the same value as what we pass as parentfp + parameter, since that's how it's used in the TP-style objects unit + b) its return value must usable to access all local data from a + routine (locals and parameters), since it's all the nested + routines have access to + c) its return value must be usable to construct a backtrace, as it's + also used by the exception handling routines + + The solution we use here, based on something similar that's done in + the MIPS port, is to generate all accesses to locals in the routine + itself SP-relative, and then after the code is generated and the local + size is known (namely, here), we change all SP-relative variables/ + parameters into FP-relative ones. This means that they'll be accessed + less efficiently from nested routines, but those accesses are indirect + anyway and at least this way they can be accessed at all + } + if current_procinfo.has_nestedprocs then + begin + current_procinfo.procdef.localst.SymList.ForEachCall(@FixupOffsets,@totalstackframesize); + current_procinfo.procdef.parast.SymList.ForEachCall(@FixupOffsets,@totalstackframesize); + end; + end; + + + procedure tcgaarch64.g_maybe_got_init(list : TAsmList); + begin + { nothing to do on Darwin or Linux } + end; + + + procedure tcgaarch64.g_restore_registers(list:TAsmList); + begin + { done in g_proc_exit } + end; + + + procedure tcgaarch64.load_regs(list: TAsmList; rt: tregistertype; lowsr, highsr: tsuperregister; sub: tsubregister); + var + ref: treference; + sr, highestsetsr: tsuperregister; + pairreg: tregister; + regcount: longint; + begin + reference_reset_base(ref,NR_SP,16,16); + ref.addressmode:=AM_POSTINDEXED; + { highest reg stored twice? } + regcount:=0; + highestsetsr:=RS_NO; + for sr:=lowsr to highsr do + if sr in rg[rt].used_in_proc then + begin + inc(regcount); + highestsetsr:=sr; + end; + if odd(regcount) then + begin + list.concat(taicpu.op_reg_ref(A_LDR,newreg(rt,highestsetsr,sub),ref)); + highestsetsr:=pred(highestsetsr); + end; + { load all (other) used registers pairwise } + pairreg:=NR_NO; + for sr:=highestsetsr downto lowsr do + if sr in rg[rt].used_in_proc then + if pairreg=NR_NO then + pairreg:=newreg(rt,sr,sub) + else + begin + list.concat(taicpu.op_reg_reg_ref(A_LDP,newreg(rt,sr,sub),pairreg,ref)); + pairreg:=NR_NO + end; + { There can't be any register left } + if pairreg<>NR_NO then + internalerror(2014112602); + end; + + + + procedure tcgaarch64.g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); + var + ref: treference; + regsstored: boolean; + sr: tsuperregister; + begin + if not nostackframe then + begin + { if no registers have been stored, we don't have to subtract the + allocated temp space from the stack pointer } + regsstored:=false; + for sr:=RS_X19 to RS_X28 do + if sr in rg[R_INTREGISTER].used_in_proc then + begin + regsstored:=true; + break; + end; + if not regsstored then + for sr:=RS_D8 to RS_D15 do + if sr in rg[R_MMREGISTER].used_in_proc then + begin + regsstored:=true; + break; + end; + { restore registers (and stack pointer) } + if regsstored then + begin + if current_procinfo.final_localsize<>0 then + handle_reg_imm12_reg(list,A_ADD,OS_ADDR,NR_SP,current_procinfo.final_localsize,NR_SP,NR_IP0,false,true); + load_regs(list,R_MMREGISTER,RS_D8,RS_D15,R_SUBMMD); + load_regs(list,R_INTREGISTER,RS_X19,RS_X28,R_SUBWHOLE); + end + else if current_procinfo.final_localsize<>0 then + { restore stack pointer } + a_load_reg_reg(list,OS_ADDR,OS_ADDR,NR_FP,NR_SP); + + { restore framepointer and return address } + reference_reset_base(ref,NR_SP,16,16); + ref.addressmode:=AM_POSTINDEXED; + list.concat(taicpu.op_reg_reg_ref(A_LDP,NR_FP,NR_LR,ref)); + end; + + { return } + list.concat(taicpu.op_none(A_RET)); + end; + + + procedure tcgaarch64.g_save_registers(list : TAsmList); + begin + { done in g_proc_entry } + end; + + + { ************* concatcopy ************ } + + procedure tcgaarch64.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(pd,1,paraloc1); + paramanager.getintparaloc(pd,2,paraloc2); + paramanager.getintparaloc(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_MMREGISTER,paramanager.get_volatile_registers_mm(pocall_default)); + a_call_name(list,'FPC_MOVE',false); + dealloccpuregisters(list,R_MMREGISTER,paramanager.get_volatile_registers_mm(pocall_default)); + dealloccpuregisters(list,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default)); + paraloc3.done; + paraloc2.done; + paraloc1.done; + end; + + + procedure tcgaarch64.g_concatcopy(list: TAsmList; const source, dest: treference; len: tcgint); + + var + sourcebasereplaced, destbasereplaced: boolean; + + { get optimal memory operation to use for loading/storing data + in an unrolled loop } + procedure getmemop(scaledop, unscaledop: tasmop; const startref, endref: treference; opsize: tcgsize; postfix: toppostfix; out memop: tasmop; out needsimplify: boolean); + begin + if (simple_ref_type(scaledop,opsize,postfix,startref)=sr_simple) and + (simple_ref_type(scaledop,opsize,postfix,endref)=sr_simple) then + begin + memop:=unscaledop; + needsimplify:=true; + end + else if (unscaledop<>A_NONE) and + (simple_ref_type(unscaledop,opsize,postfix,startref)=sr_simple) and + (simple_ref_type(unscaledop,opsize,postfix,endref)=sr_simple) then + begin + memop:=unscaledop; + needsimplify:=false; + end + else + begin + memop:=scaledop; + needsimplify:=true; + end; + end; + + { adjust the offset and/or addressing mode after a load/store so it's + correct for the next one of the same size } + procedure updaterefafterloadstore(var ref: treference; oplen: longint); + begin + case ref.addressmode of + AM_OFFSET: + inc(ref.offset,oplen); + AM_POSTINDEXED: + { base register updated by instruction, next offset can remain + the same } + ; + AM_PREINDEXED: + begin + { base register updated by instruction -> next instruction can + use post-indexing with offset = sizeof(operation) } + ref.offset:=0; + ref.addressmode:=AM_OFFSET; + end; + end; + end; + + { generate a load/store and adjust the reference offset to the next + memory location if necessary } + procedure genloadstore(list: TAsmList; op: tasmop; reg: tregister; var ref: treference; postfix: toppostfix; opsize: tcgsize); + begin + list.concat(setoppostfix(taicpu.op_reg_ref(op,reg,ref),postfix)); + updaterefafterloadstore(ref,tcgsize2size[opsize]); + end; + + { generate a dual load/store (ldp/stp) and adjust the reference offset to + the next memory location if necessary } + procedure gendualloadstore(list: TAsmList; op: tasmop; reg1, reg2: tregister; var ref: treference; postfix: toppostfix; opsize: tcgsize); + begin + list.concat(setoppostfix(taicpu.op_reg_reg_ref(op,reg1,reg2,ref),postfix)); + updaterefafterloadstore(ref,tcgsize2size[opsize]*2); + end; + + { turn a reference into a pre- or post-indexed reference for use in a + load/store of a particular size } + procedure makesimpleforcopy(list: TAsmList; var scaledop: tasmop; opsize: tcgsize; postfix: toppostfix; forcepostindexing: boolean; var ref: treference; var basereplaced: boolean); + var + tmpreg: tregister; + scaledoffset: longint; + orgaddressmode: taddressmode; + begin + scaledoffset:=tcgsize2size[opsize]; + if scaledop in [A_LDP,A_STP] then + scaledoffset:=scaledoffset*2; + { can we use the reference as post-indexed without changes? } + if forcepostindexing then + begin + orgaddressmode:=ref.addressmode; + ref.addressmode:=AM_POSTINDEXED; + if (orgaddressmode=AM_POSTINDEXED) or + ((ref.offset=0) and + (simple_ref_type(scaledop,opsize,postfix,ref)=sr_simple)) then + begin + { just change the post-indexed offset to the access size } + ref.offset:=scaledoffset; + { and replace the base register if that didn't happen yet + (could be sp or a regvar) } + if not basereplaced then + begin + tmpreg:=getaddressregister(list); + a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.base,tmpreg); + ref.base:=tmpreg; + basereplaced:=true; + end; + exit; + end; + ref.addressmode:=orgaddressmode; + end; +{$ifdef dummy} + This could in theory be useful in case you have a concatcopy from + e.g. x1+255 to x1+267 *and* the reference is aligned, but this seems + very unlikely. Disabled because it still needs fixes, as it + also generates pre-indexed loads right now at the very end for the + left-over gencopies + + { can we turn it into a pre-indexed reference for free? (after the + first operation, it will be turned into an offset one) } + if not forcepostindexing and + (ref.offset<>0) then + begin + orgaddressmode:=ref.addressmode; + ref.addressmode:=AM_PREINDEXED; + tmpreg:=ref.base; + if not basereplaced and + (ref.base=tmpreg) then + begin + tmpreg:=getaddressregister(list); + a_load_reg_reg(list,OS_ADDR,OS_ADDR,ref.base,tmpreg); + ref.base:=tmpreg; + basereplaced:=true; + end; + if simple_ref_type(scaledop,opsize,postfix,ref)<>sr_simple then + make_simple_ref(list,scaledop,opsize,postfix,ref,NR_NO); + exit; + end; +{$endif dummy} + if not forcepostindexing then + begin + ref.addressmode:=AM_OFFSET; + make_simple_ref(list,scaledop,opsize,postfix,ref,NR_NO); + { this may still cause problems if the final offset is no longer + a simple ref; it's a bit complicated to pass all information + through at all places and check that here, so play safe: we + currently never generate unrolled copies for more than 64 + bytes (32 with non-double-register copies) } + if ref.index=NR_NO then + begin + if ((scaledop in [A_LDP,A_STP]) and + (ref.offset<((64-8)*tcgsize2size[opsize]))) or + ((scaledop in [A_LDUR,A_STUR]) and + (ref.offset<(255-8*tcgsize2size[opsize]))) or + ((scaledop in [A_LDR,A_STR]) and + (ref.offset<((4096-8)*tcgsize2size[opsize]))) then + exit; + end; + end; + tmpreg:=getaddressregister(list); + a_loadaddr_ref_reg(list,ref,tmpreg); + basereplaced:=true; + if forcepostindexing then + begin + reference_reset_base(ref,tmpreg,scaledoffset,ref.alignment); + ref.addressmode:=AM_POSTINDEXED; + end + else + begin + reference_reset_base(ref,tmpreg,0,ref.alignment); + ref.addressmode:=AM_OFFSET; + end + end; + + { prepare a reference for use by gencopy. This is done both after the + unrolled and regular copy loop -> get rid of post-indexing mode, make + sure ref is valid } + procedure preparecopy(list: tasmlist; scaledop, unscaledop: tasmop; var ref: treference; opsize: tcgsize; postfix: toppostfix; out op: tasmop; var basereplaced: boolean); + var + simplify: boolean; + begin + if ref.addressmode=AM_POSTINDEXED then + ref.offset:=tcgsize2size[opsize]; + getmemop(scaledop,scaledop,ref,ref,opsize,postfix,op,simplify); + if simplify then + begin + makesimpleforcopy(list,scaledop,opsize,postfix,false,ref,basereplaced); + op:=scaledop; + end; + end; + + { generate a copy from source to dest of size opsize/postfix } + procedure gencopy(list: TAsmList; var source, dest: treference; postfix: toppostfix; opsize: tcgsize); + var + reg: tregister; + loadop, storeop: tasmop; + begin + preparecopy(list,A_LDR,A_LDUR,source,opsize,postfix,loadop,sourcebasereplaced); + preparecopy(list,A_STR,A_STUR,dest,opsize,postfix,storeop,destbasereplaced); + reg:=getintregister(list,opsize); + genloadstore(list,loadop,reg,source,postfix,opsize); + genloadstore(list,storeop,reg,dest,postfix,opsize); + end; + + + { copy the leftovers after an unrolled or regular copy loop } + procedure gencopyleftovers(list: TAsmList; var source, dest: treference; len: longint); + begin + { stop post-indexing if we did so in the loop, since in that case all + offsets definitely can be represented now } + if source.addressmode=AM_POSTINDEXED then + begin + source.addressmode:=AM_OFFSET; + source.offset:=0; + end; + if dest.addressmode=AM_POSTINDEXED then + begin + dest.addressmode:=AM_OFFSET; + dest.offset:=0; + end; + { transfer the leftovers } + if len>=8 then + begin + dec(len,8); + gencopy(list,source,dest,PF_NONE,OS_64); + end; + if len>=4 then + begin + dec(len,4); + gencopy(list,source,dest,PF_NONE,OS_32); + end; + if len>=2 then + begin + dec(len,2); + gencopy(list,source,dest,PF_H,OS_16); + end; + if len>=1 then + begin + dec(len); + gencopy(list,source,dest,PF_B,OS_8); + end; + end; + + + const + { load_length + loop dec + cbnz } + loopoverhead=12; + { loop overhead + load + store } + totallooplen=loopoverhead + 8; + var + totalalign: longint; + maxlenunrolled: tcgint; + loadop, storeop: tasmop; + opsize: tcgsize; + postfix: toppostfix; + tmpsource, tmpdest: treference; + scaledstoreop, unscaledstoreop, + scaledloadop, unscaledloadop: tasmop; + regs: array[1..8] of tregister; + countreg: tregister; + i, regcount: longint; + hl: tasmlabel; + simplifysource, simplifydest: boolean; + begin + if len=0 then + exit; + sourcebasereplaced:=false; + destbasereplaced:=false; + { maximum common alignment } + totalalign:=max(1,newalignment(source.alignment,dest.alignment)); + { use a simple load/store? } + if (len in [1,2,4,8]) and + ((totalalign>=(len div 2)) or + (source.alignment=len) or + (dest.alignment=len)) then + begin + opsize:=int_cgsize(len); + a_load_ref_ref(list,opsize,opsize,source,dest); + exit; + end; + + { alignment > length is not useful, and would break some checks below } + while totalalign>len do + totalalign:=totalalign div 2; + + { operation sizes to use based on common alignment } + case totalalign of + 1: + begin + postfix:=PF_B; + opsize:=OS_8; + end; + 2: + begin + postfix:=PF_H; + opsize:=OS_16; + end; + 4: + begin + postfix:=PF_None; + opsize:=OS_32; + end + else + begin + totalalign:=8; + postfix:=PF_None; + opsize:=OS_64; + end; + end; + { maximum length to handled with an unrolled loop (4 loads + 4 stores) } + maxlenunrolled:=min(totalalign,8)*4; + { ldp/stp -> 2 registers per instruction } + if (totalalign>=4) and + (len>=totalalign*2) then + begin + maxlenunrolled:=maxlenunrolled*2; + scaledstoreop:=A_STP; + scaledloadop:=A_LDP; + unscaledstoreop:=A_NONE; + unscaledloadop:=A_NONE; + end + else + begin + scaledstoreop:=A_STR; + scaledloadop:=A_LDR; + unscaledstoreop:=A_STUR; + unscaledloadop:=A_LDUR; + end; + { we only need 4 instructions extra to call FPC_MOVE } + if cs_opt_size in current_settings.optimizerswitches then + maxlenunrolled:=maxlenunrolled div 2; + if (len>maxlenunrolled) and + (len>totalalign*8) then + begin + g_concatcopy_move(list,source,dest,len); + exit; + end; + + simplifysource:=true; + simplifydest:=true; + tmpsource:=source; + tmpdest:=dest; + { can we directly encode all offsets in an unrolled loop? } + if len<=maxlenunrolled then + begin +{$ifdef extdebug} + list.concat(tai_comment.Create(strpnew('concatcopy unrolled loop; len/opsize/align: '+tostr(len)+'/'+tostr(tcgsize2size[opsize])+'/'+tostr(totalalign)))); +{$endif extdebug} + { the leftovers will be handled separately -> -(len mod opsize) } + inc(tmpsource.offset,len-(len mod tcgsize2size[opsize])); + { additionally, the last regular load/store will be at + offset+len-opsize (if len-(len mod opsize)>len) } + if tmpsource.offset>source.offset then + dec(tmpsource.offset,tcgsize2size[opsize]); + getmemop(scaledloadop,unscaledloadop,source,tmpsource,opsize,postfix,loadop,simplifysource); + inc(tmpdest.offset,len-(len mod tcgsize2size[opsize])); + if tmpdest.offset>dest.offset then + dec(tmpdest.offset,tcgsize2size[opsize]); + getmemop(scaledstoreop,unscaledstoreop,dest,tmpdest,opsize,postfix,storeop,simplifydest); + tmpsource:=source; + tmpdest:=dest; + { if we can't directly encode all offsets, simplify } + if simplifysource then + begin + loadop:=scaledloadop; + makesimpleforcopy(list,loadop,opsize,postfix,false,tmpsource,sourcebasereplaced); + end; + if simplifydest then + begin + storeop:=scaledstoreop; + makesimpleforcopy(list,storeop,opsize,postfix,false,tmpdest,destbasereplaced); + end; + regcount:=len div tcgsize2size[opsize]; + { in case we transfer two registers at a time, we copy an even + number of registers } + if loadop=A_LDP then + regcount:=regcount and not(1); + { initialise for dfa } + regs[low(regs)]:=NR_NO; + { max 4 loads/stores -> max 8 registers (in case of ldp/stdp) } + for i:=1 to regcount do + regs[i]:=getintregister(list,opsize); + if loadop=A_LDP then + begin + { load registers } + for i:=1 to (regcount div 2) do + gendualloadstore(list,loadop,regs[i*2-1],regs[i*2],tmpsource,postfix,opsize); + { store registers } + for i:=1 to (regcount div 2) do + gendualloadstore(list,storeop,regs[i*2-1],regs[i*2],tmpdest,postfix,opsize); + end + else + begin + for i:=1 to regcount do + genloadstore(list,loadop,regs[i],tmpsource,postfix,opsize); + for i:=1 to regcount do + genloadstore(list,storeop,regs[i],tmpdest,postfix,opsize); + end; + { leftover } + len:=len-regcount*tcgsize2size[opsize]; +{$ifdef extdebug} + list.concat(tai_comment.Create(strpnew('concatcopy unrolled loop leftover: '+tostr(len)))); +{$endif extdebug} + end + else + begin +{$ifdef extdebug} + list.concat(tai_comment.Create(strpnew('concatcopy regular loop; len/align: '+tostr(len)+'/'+tostr(totalalign)))); +{$endif extdebug} + { regular loop -> definitely use post-indexing } + loadop:=scaledloadop; + makesimpleforcopy(list,loadop,opsize,postfix,true,tmpsource,sourcebasereplaced); + storeop:=scaledstoreop; + makesimpleforcopy(list,storeop,opsize,postfix,true,tmpdest,destbasereplaced); + current_asmdata.getjumplabel(hl); + countreg:=getintregister(list,OS_32); + if loadop=A_LDP then + a_load_const_reg(list,OS_32,len div tcgsize2size[opsize]*2,countreg) + else + a_load_const_reg(list,OS_32,len div tcgsize2size[opsize],countreg); + a_label(list,hl); + a_op_const_reg(list,OP_SUB,OS_32,1,countreg); + if loadop=A_LDP then + begin + regs[1]:=getintregister(list,opsize); + regs[2]:=getintregister(list,opsize); + gendualloadstore(list,loadop,regs[1],regs[2],tmpsource,postfix,opsize); + gendualloadstore(list,storeop,regs[1],regs[2],tmpdest,postfix,opsize); + end + else + begin + regs[1]:=getintregister(list,opsize); + genloadstore(list,loadop,regs[1],tmpsource,postfix,opsize); + genloadstore(list,storeop,regs[1],tmpdest,postfix,opsize); + end; + list.concat(taicpu.op_reg_sym_ofs(A_CBNZ,countreg,hl,0)); + len:=len mod tcgsize2size[opsize]; + end; + gencopyleftovers(list,tmpsource,tmpdest,len); + end; + + + procedure tcgaarch64.g_adjust_self_value(list:TAsmList;procdef: tprocdef;ioffset: tcgint); + begin + { This method is integrated into g_intf_wrapper and shouldn't be called separately } + InternalError(2013020102); + end; + + + procedure tcgaarch64.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint); + var + make_global: boolean; + href: treference; + hsym: tsym; + paraloc: pcgparalocation; + op: tasmop; + 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_library 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)) + else + list.concat(Tai_symbol.Createname(labelname,AT_FUNCTION,0)); + + { 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: + handle_reg_imm12_reg(list,A_SUB,paraloc^.size,paraloc^.register,ioffset,paraloc^.register,NR_IP0,false,true); + else + internalerror(2010103102); + end; + + if (po_virtualmethod in procdef.procoptions) and + not is_objectpascal_helper(procdef.struct) then + begin + if (procdef.extnumber=$ffff) then + Internalerror(200006139); + { mov 0(%rdi),%rax ; load vmt} + reference_reset_base(href,paraloc^.register,0,sizeof(pint)); + getcpuregister(list,NR_IP0); + a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_IP0); + { jmp *vmtoffs(%eax) ; method offs } + reference_reset_base(href,NR_IP0,tobjectdef(procdef.struct).vmtmethodoffset(procdef.extnumber),sizeof(pint)); + op:=A_LDR; + make_simple_ref(list,op,OS_ADDR,PF_None,href,NR_IP0); + list.concat(taicpu.op_reg_ref(op,NR_IP0,href)); + ungetcpuregister(list,NR_IP0); + list.concat(taicpu.op_reg(A_BR,NR_IP0)); + end + else + a_jmp_name(list,procdef.mangledname); + list.concat(Tai_symbol_end.Createname(labelname)); + end; + + + procedure create_codegen; + begin + cg:=tcgaarch64.Create; + cg128:=tcg128.Create; + end; + +end. diff --git a/fpcsrc/compiler/aarch64/cpubase.pas b/fpcsrc/compiler/aarch64/cpubase.pas index 5d28471c..7b3afd30 100644 --- a/fpcsrc/compiler/aarch64/cpubase.pas +++ b/fpcsrc/compiler/aarch64/cpubase.pas @@ -1,7 +1,8 @@ { Copyright (c) 1998-2012 by Florian Klaempfl and Peter Vreman + Copyright (c) 2014 by Jonas Maebe and Florian Klaempfl - Contains the base types for ARM64 + Contains the base types for Aarch64 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 @@ -68,14 +69,22 @@ unit cpubase; { Available Superregisters } {$i ra64sup.inc} + RS_IP0 = RS_X16; + RS_IP1 = RS_X17; + R_SUBWHOLE = R_SUBQ; { Available Registers } {$i ra64con.inc} + NR_IP0 = NR_X16; + NR_IP1 = NR_X17; + { Integer Super registers first and last } first_int_supreg = RS_X0; - first_int_imreg = $20; + { xzr and sp take up a separate super register because some instructions + are ambiguous otherwise } + first_int_imreg = $21; { Integer Super registers first and last } first_fpu_supreg = RS_S0; @@ -92,7 +101,7 @@ unit cpubase; The value of this constant is equal to the constant PARM_BOUNDARY / BITS_PER_UNIT in the GCC source. } - std_param_align = 4; + std_param_align = 8; { TODO: Calculate bsstart} regnumber_count_bsstart = 128; @@ -109,7 +118,7 @@ unit cpubase; {$i ra64dwa.inc} ); { registers which may be destroyed by calls } - VOLATILE_INTREGISTERS = [RS_X0..RS_X18,RS_X29..RS_X30]; + VOLATILE_INTREGISTERS = [RS_X0..RS_X18,RS_X30]; VOLATILE_MMREGISTERS = [RS_D0..RS_D7,RS_D16..RS_D31]; type @@ -126,16 +135,23 @@ unit cpubase; TOpPostfix = (PF_None, { update condition flags } PF_S, - { load/store } - PF_B,PF_SB,PF_H,PF_SH + { load/store sizes } + PF_B,PF_SB,PF_H,PF_SH,PF_W,PF_SW ); TOpPostfixes = set of TOpPostfix; const - oppostfix2str : array[TOpPostfix] of string[2] = ('', + tcgsizep2size: array[OS_NO..OS_F128] of byte = + {OS_NO } + (0, + {OS_8,OS_16,OS_32,OS_64,OS_128,OS_S8,OS_S16,OS_S32,OS_S64,OS_S128} + 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, + {OS_F32,OS_F64,OS_F80,OS_C64,OS_F128,} + 2, 3, 0, 3, 4); + oppostfix2str: array[TOpPostfix] of string[2] = ('', 's', - 'b','sb','h','sh'); + 'b','sb','h','sh','w','sw'); {***************************************************************************** Conditions @@ -150,13 +166,15 @@ unit cpubase; TAsmConds = set of TAsmCond; const + C_CS = C_HS; + C_CC = C_LO; cond2str : array[TAsmCond] of string[2]=('', 'eq','ne','hs','lo','mi','pl','vs','vc','hi','ls', 'ge','lt','gt','le','al','nv' ); uppercond2str : array[TAsmCond] of string[2]=('', - 'EQ','NE','hs','LO','MI','PL','VS','VC','HI','LS', + 'EQ','NE','HS','LO','MI','PL','VS','VC','HI','LS', 'GE','LT','GT','LE','AL','NV' ); @@ -168,12 +186,28 @@ unit cpubase; TResFlags = (F_EQ,F_NE,F_CS,F_CC,F_MI,F_PL,F_VS,F_VC,F_HI,F_LS, F_GE,F_LT,F_GT,F_LE); + const + F_HS = F_CS; + F_LO = F_CC; + {***************************************************************************** Operands *****************************************************************************} + type taddressmode = (AM_OFFSET,AM_PREINDEXED,AM_POSTINDEXED); - tshiftmode = (SM_None,SM_LSL,SM_LSR,SM_ASR,SM_ROR); + + tshiftmode = (SM_None, + { shifted register instructions. LSL can also be used for + the index register of certain loads/stores } + SM_LSL,SM_LSR,SM_ASR, + { extended register instructions: zero/sign extension + + optional shift (interpreted as LSL after extension) + -- the index register of certain loads/stores can be + extended via (s|u)xtw with a shiftval of either 0 or + log2(transfer size of the load/store) + } + SM_UXTB,SM_UXTH,SM_UXTW,SM_UXTX,SM_SXTB,SM_SXTH,SM_SXTW,SM_SXTX); tupdatereg = (UR_None,UR_Update); @@ -184,12 +218,6 @@ unit cpubase; shiftimm : byte; end; - tcpumodeflag = (mfA, mfI, mfF); - tcpumodeflags = set of tcpumodeflag; - - tspecialregflag = (srC, srX, srS, srF); - tspecialregflags = set of tspecialregflag; - {***************************************************************************** Constants *****************************************************************************} @@ -201,6 +229,10 @@ unit cpubase; maxfpuregs = 32; maxaddrregs = 0; + shiftedregmodes = [SM_LSL,SM_UXTB,SM_UXTH,SM_UXTW,SM_UXTX,SM_SXTB,SM_SXTH,SM_SXTW,SM_SXTX]; + extendedregmodes = [SM_LSL,SM_LSR,SM_ASR]; + + {***************************************************************************** Operand Sizes *****************************************************************************} @@ -232,17 +264,23 @@ unit cpubase; Generic Register names *****************************************************************************} - NR_SP = NR_XZR; - RS_SP = RS_XZR; - NR_WSP = NR_WZR; - RS_WSP = RS_WZR; + + NR_FP = NR_X29; + RS_FP = RS_X29; + NR_WFP = NR_W29; + RS_WFP = RS_W29; + + NR_LR = NR_X30; + RS_LR = RS_X30; + NR_WLR = NR_W30; + RS_WLR = RS_W30; { Stack pointer register } NR_STACK_POINTER_REG = NR_SP; RS_STACK_POINTER_REG = RS_SP; - { Frame pointer register (initialized in tarmprocinfo.init_framepointer) } - RS_FRAME_POINTER_REG: tsuperregister = RS_X29; - NR_FRAME_POINTER_REG: tregister = NR_X29; + { Frame pointer register } + NR_FRAME_POINTER_REG = NR_X29; + RS_FRAME_POINTER_REG = RS_X29; { Register for addressing absolute data in a position independant way, such as in PIC code. The exact meaning is ABI specific. For further information look at GCC source : PIC_OFFSET_TABLE_REGNUM @@ -307,6 +345,9 @@ unit cpubase; function dwarf_reg(r:tregister):shortint; + function is_shifter_const(d: aint; size: tcgsize): boolean; + + implementation uses @@ -329,13 +370,24 @@ unit cpubase; function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister; begin case regtype of + R_INTREGISTER: + begin + case s of + { there's only Wn and Xn } + OS_64, + OS_S64: + cgsize2subreg:=R_SUBWHOLE; + else + cgsize2subreg:=R_SUBD; + end; + end; R_MMREGISTER: begin case s of OS_F32: - cgsize2subreg:=R_SUBFS; + cgsize2subreg:=R_SUBMMS; OS_F64: - cgsize2subreg:=R_SUBFD; + cgsize2subreg:=R_SUBMMD; else internalerror(2009112701); end; @@ -349,18 +401,22 @@ unit cpubase; function reg_cgsize(const reg: tregister): tcgsize; begin case getregtype(reg) of - R_INTREGISTER : - reg_cgsize:=OS_32; - R_FPUREGISTER : - reg_cgsize:=OS_F80; + R_INTREGISTER: + case getsubreg(reg) of + R_SUBD: + result:=OS_32 + else + result:=OS_64; + end; R_MMREGISTER : begin case getsubreg(reg) of - R_SUBFD, - R_SUBWHOLE: + R_SUBMMD: result:=OS_F64; - R_SUBFS: + R_SUBMMS: result:=OS_F32; + R_SUBMMWHOLE: + result:=OS_M128; else internalerror(2009112903); end; @@ -373,9 +429,7 @@ unit cpubase; function is_calljmp(o:tasmop):boolean;{$ifdef USEINLINE}inline;{$endif USEINLINE} begin - { This isn't 100% perfect because the arm allows jumps also by writing to PC=R15. - To overcome this problem we simply forbid that FPC generates jumps by loading R15 } - is_calljmp:= o in [A_B,A_BLR,A_RET]; + is_calljmp:=o in [A_B,A_BL,A_BLR,A_RET,A_CBNZ,A_CBZ,A_TBNZ,A_TBZ]; end; @@ -391,8 +445,8 @@ unit cpubase; function flags_to_cond(const f: TResFlags) : TAsmCond; const - flag_2_cond: array[F_EQ..F_LE] of TAsmCond = - (C_EQ,C_NE,C_HI,C_LO,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS, + flag_2_cond: array[TResFlags] of TAsmCond = + (C_EQ,C_NE,C_HS,C_LO,C_MI,C_PL,C_VS,C_VC,C_HI,C_LS, C_GE,C_LT,C_GT,C_LE); begin if f>high(flag_2_cond) then @@ -434,7 +488,7 @@ unit cpubase; function inverse_cond(const c: TAsmCond): TAsmCond; {$ifdef USEINLINE}inline;{$endif USEINLINE} const inverse: array[TAsmCond] of TAsmCond=(C_None, - C_NE,C_EQ,C_LO,C_HI,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI, + C_NE,C_EQ,C_LO,C_HS,C_PL,C_MI,C_VC,C_VS,C_LS,C_HI, C_LT,C_GE,C_LE,C_GT,C_None,C_None ); begin @@ -456,4 +510,112 @@ unit cpubase; end; + function is_shifter_const(d: aint; size: tcgsize): boolean; + var + pattern, checkpattern: qword; + patternlen, maxbits, replicatedlen: longint; + rightmostone, rightmostzero, checkbit, secondrightmostbit: longint; + begin + result:=false; + { patterns with all bits 0 or 1 cannot be represented this way } + if (d=0) then + exit; + case size of + OS_64, + OS_S64: + begin + if d=-1 then + exit; + maxbits:=64; + end + else + begin + if longint(d)=-1 then + exit; + { we'll generate a 32 bit pattern -> ignore upper sign bits in + case of negative longint value } + d:=cardinal(d); + maxbits:=32; + end; + end; + { "The Logical (immediate) instructions accept a bitmask immediate value + that is a 32-bit pattern or a 64-bit pattern viewed as a vector of + identical elements of size e = 2, 4, 8, 16, 32 or, 64 bits. Each + element contains the same sub-pattern, that is a single run of + 1 to (e - 1) nonzero bits from bit 0 followed by zero bits, then + rotated by 0 to (e - 1) bits." (ARMv8 ARM) + + Rather than generating all possible patterns and checking whether they + match our constant, we check whether the lowest 2/4/8/... bits are + a valid pattern, and if so whether the constant consists of a + replication of this pattern. Such a valid pattern has the form of + either (regexp notation) + * 1+0+1* + * 0+1+0* } + patternlen:=2; + while patternlen<=maxbits do + begin + { try lowest bits of d as pattern } + if patternlen<>64 then + pattern:=qword(d) and ((qword(1) shl patternlen)-1) + else + pattern:=qword(d); + { valid pattern? If it contains too many 1<->0 transitions, larger + parts of d cannot be a valid pattern either } + rightmostone:=BsfQWord(pattern); + rightmostzero:=BsfQWord(not(pattern)); + { pattern all ones or zeroes -> not a valid pattern (but larger ones + can still be valid, since we have too few transitions) } + if (rightmostonerightmostzero then + begin + { we have .*1*0* -> check next zero position by shifting + out the existing zeroes (shr rightmostone), inverting and + then again looking for the rightmost one position } + checkpattern:=not(pattern); + checkbit:=rightmostone; + end + else + begin + { same as above, but for .*0*1* } + checkpattern:=pattern; + checkbit:=rightmostzero; + end; + secondrightmostbit:=BsfQWord(checkpattern shr checkbit)+checkbit; + { if this position is >= patternlen -> ok (1 transition), + otherwise we now have 2 transitions and have to check for a + third (if there is one, abort) + + bsf returns 255 if no 1 bit is found, so in that case it's + also ok + } + if secondrightmostbit multiply by number of elements + in the array } + inc(elecount,tarraydef(p).elecount*tmpelecount); + if elecount>4 then + exit; + end; + else + result:=is_hfa_internal(tarraydef(p).elementdef,basedef,elecount); + end; + end; + floatdef: + begin + if not assigned(basedef) then + basedef:=p + else if basedef<>p then + exit; + inc(elecount); + result:=true; + end; + recorddef: + begin + for i:=0 to tabstractrecorddef(p).symtable.symlist.count-1 do + begin + sym:=tsym(tabstractrecorddef(p).symtable.symlist[i]); + if sym.typ<>fieldvarsym then + continue; + if not is_hfa_internal(tfieldvarsym(sym).vardef,basedef,elecount) then + exit + end; + result:=true; + end; + else + exit + end; end; - function Is_HFA(p : tdef) : boolean; + { Returns whether a def is a "homogeneous float array" at the machine level. + This means that in the memory layout, the def only consists of maximally + 4 floating point values that appear consecutively in memory } + function is_hfa(p: tdef; out basedef: tdef) : boolean; + var + elecount: longint; begin result:=false; + basedef:=nil; + elecount:=0; + result:=is_hfa_internal(p,basedef,elecount); + result:= + result and + (elecount>0) and + (elecount<=4) and + (p.size=basedef.size*elecount) end; - function getparaloc(calloption : tproccalloption; p : tdef; isvariadic: boolean) : tcgloc; + function getparaloc(calloption: tproccalloption; p: tdef): tcgloc; + var + hfabasedef: tdef; begin { Later, the LOC_REFERENCE is in most cases changed into LOC_REGISTER if push_addr_param for the def is true @@ -134,7 +190,10 @@ unit cpupara; classrefdef: getparaloc:=LOC_REGISTER; recorddef: - getparaloc:=LOC_REGISTER; + if not is_hfa(p,hfabasedef) then + getparaloc:=LOC_REGISTER + else + getparaloc:=LOC_MMREGISTER; objectdef: getparaloc:=LOC_REGISTER; stringdef: @@ -147,12 +206,12 @@ unit cpupara; filedef: getparaloc:=LOC_REGISTER; arraydef: - getparaloc:=LOC_REFERENCE; - setdef: - if is_smallset(p) then + if not is_hfa(p,hfabasedef) then getparaloc:=LOC_REGISTER else - getparaloc:=LOC_REFERENCE; + getparaloc:=LOC_MMREGISTER; + setdef: + getparaloc:=LOC_REGISTER; variantdef: getparaloc:=LOC_REGISTER; { avoid problems with errornous definitions } @@ -164,7 +223,9 @@ unit cpupara; end; - function taarch64paramanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean; + function taarch64paramanager.push_addr_param(varspez: tvarspez; def :tdef; calloption: tproccalloption): boolean; + var + hfabasedef: tdef; begin result:=false; if varspez in [vs_var,vs_out,vs_constref] then @@ -174,19 +235,36 @@ unit cpupara; end; case def.typ of objectdef: - result:=not(Is_HFA(def) and (is_object(def) and ((varspez=vs_const) or (def.size=0)); + result:=is_object(def); recorddef: - { note: should this ever be changed, make sure that const records - are always passed by reference for calloption=pocall_mwpascal } - result:=(varspez=vs_const) or (def.size=0); + { ABI: any composite > 16 bytes that not a hfa/hva + Special case: MWPascal, which passes all const parameters by + reference for compatibility reasons + } + result:= + ((varspez=vs_const) and + (calloption=pocall_mwpascal)) or + (not is_hfa(def,hfabasedef) and + (def.size>16)); variantdef, formaldef: result:=true; + { arrays are composites and hence treated the same as records by the + ABI (watch out for C, where an array is a pointer) + Also: all other platforms pass const arrays by reference. Do the + same here, because there is too much hacky code out there that + relies on this ("array[0..0] of x" passed as const parameter and + then indexed beyond its bounds) } arraydef: - result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or - is_open_array(def) or - is_array_of_const(def) or - is_array_constructor(def); + result:= + (calloption in cdecl_pocalls) or + is_open_array(def) or + is_array_of_const(def) or + is_array_constructor(def) or + ((tarraydef(def).highrange>=tarraydef(def).lowrange) and + ((varspez=vs_const) or + (not is_hfa(def,hfabasedef) and + (def.size>16)))); setdef : result:=def.size>16; stringdef : @@ -195,511 +273,370 @@ unit cpupara; end; - function taarch64paramanager.ret_in_param(def:tdef;pd:tabstractprocdef):boolean; - var - i: longint; - sym: tsym; - fpufield: boolean; + function taarch64paramanager.ret_in_param(def: tdef; pd: tabstractprocdef): boolean; begin if handle_common_ret_in_param(def,pd,result) then exit; - case def.typ of - recorddef: - begin - result:=def.size>4; - if not result and - (target_info.abi in [abi_default,abi_armeb]) then - begin - { in case of the old ARM abi (APCS), a struct is returned in - a register only if it is simple. And what is a (non-)simple - struct: - - "A non-simple type is any non-floating-point type of size - greater than one word (including structures containing only - floating-point fields), and certain single-word structured - types." - (-- ARM APCS documentation) - - So only floating point types or more than one word -> - definitely non-simple (more than one word is already - checked above). This includes unions/variant records with - overlaid floating point and integer fields. - - Smaller than one word struct types are simple if they are - "integer-like", and: - - "A structure is termed integer-like if its size is less than - or equal to one word, and the offset of each of its - addressable subfields is zero." - (-- ARM APCS documentation) - - An "addressable subfield" is a field of which you can take - the address, which in practive means any non-bitfield. - In Pascal, there is no way to express the difference that - you can have in C between "char" and "int :8". In this - context, we use the fake distinction that a type defined - inside the record itself (such as "a: 0..255;") indicates - a bitpacked field while a field using a different type - (such as "a: byte;") is not. - } - for i:=0 to trecorddef(def).symtable.SymList.count-1 do - begin - sym:=tsym(trecorddef(def).symtable.SymList[i]); - if sym.typ<>fieldvarsym then - continue; - { bitfield -> ignore } - if (trecordsymtable(trecorddef(def).symtable).usefieldalignment=bit_alignment) and - (tfieldvarsym(sym).vardef.typ in [orddef,enumdef]) and - (tfieldvarsym(sym).vardef.owner.defowner=def) then - continue; - { all other fields must be at offset zero } - if tfieldvarsym(sym).fieldoffset<>0 then - begin - result:=true; - exit; - end; - { floating point field -> also by reference } - if tfieldvarsym(sym).vardef.typ=floatdef then - begin - result:=true; - exit; - end; - end; - end; - end; - procvardef: - if not tprocvardef(def).is_addressonly then - result:=true - else - result:=false - else - result:=inherited ret_in_param(def,pd); - end; - end; - - - procedure taarch64paramanager.init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister); - begin - curintreg:=RS_R0; - curfloatreg:=RS_F0; - curmmreg:=RS_D0; - cur_stack_offset:=0; - sparesinglereg := NR_NO; + { ABI: if the parameter would be passed in registers, it is returned + in those registers; otherwise, it's returned by reference } + result:=push_addr_param(vs_value,def,pd.proccalloption); end; - function taarch64paramanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; - var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister; isvariadic: boolean):longint; - + procedure taarch64paramanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean); var - nextintreg,nextfloatreg,nextmmreg : tsuperregister; - paradef : tdef; - paraloc : pcgparalocation; - stack_offset : aword; - hp : tparavarsym; - loc : tcgloc; - paracgsize : tcgsize; - paralen : longint; - i : integer; - firstparaloc: boolean; - - procedure assignintreg; - begin - { In case of po_delphi_nested_cc, the parent frame pointer - is always passed on the stack. } - if (nextintreg<=RS_R3) and - (not(vo_is_parentfp in hp.varoptions) or - not(po_delphi_nested_cc in p.procoptions)) then - begin - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE); - inc(nextintreg); - end - else - begin - paraloc^.loc:=LOC_REFERENCE; - paraloc^.reference.index:=NR_STACK_POINTER_REG; - paraloc^.reference.offset:=stack_offset; - inc(stack_offset,4); - end; - end; - - + hp: tparavarsym; + i: longint; begin - result:=0; - nextintreg:=curintreg; - nextfloatreg:=curfloatreg; - nextmmreg:=curmmreg; - stack_offset:=cur_stack_offset; - for i:=0 to paras.count-1 do begin hp:=tparavarsym(paras[i]); - paradef:=hp.vardef; - - hp.paraloc[side].reset; - - { currently only support C-style array of const, - there should be no location assigned to the vararg array itself } - 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_R0; - paraloc^.size:=OS_ADDR; - break; - end; - - if push_addr_param(hp.varspez,paradef,p.proccalloption) then + { hidden function result parameter is passed in X8 (doesn't have to + be valid on return) according to the ABI + + -- don't follow the ABI for managed types, because + a) they are passed in registers as parameters, so we should also + return them in a register to be ABI-compliant (which we can't + because the entire compiler is built around the idea that + they are returned by reference, for ref-counting performance + and Delphi-compatibility reasons) + b) there are hacks in the system unit that expect that you can + call + function f: com_interface; + as + procedure p(out o: obj); + That can only work in case we do not use x8 to return them + from the function, but the regular first parameter register. + + As the ABI says this behaviour is ok for C++ classes with a + non-trivial copy constructor or destructor, it seems reasonable + for us to do this for managed types as well.} + if (vo_is_funcret in hp.varoptions) and + not is_managed_type(hp.vardef) then begin - paradef:=getpointerdef(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)]; - loc := getparaloc(p.proccalloption,paradef,isvariadic); - if (paradef.typ in [objectdef,arraydef,recorddef]) and - not is_special_array(paradef) and - (hp.varspez in [vs_value,vs_const]) then - paracgsize := int_cgsize(paralen) - else + hp.paraloc[side].reset; + hp.paraloc[side].size:=OS_ADDR; + hp.paraloc[side].alignment:=voidpointertype.alignment; + hp.paraloc[side].intsize:=voidpointertype.size; + hp.paraloc[side].def:=getpointerdef(hp.vardef); + with hp.paraloc[side].add_location^ do begin - paracgsize:=def_cgsize(paradef); - { for things like formaldef } - if (paracgsize=OS_NO) then - begin - paracgsize:=OS_ADDR; - paralen:=tcgsize2size[OS_ADDR]; - paradef:=voidpointertype; - end; + size:=OS_ADDR; + def:=hp.paraloc[side].def; + loc:=LOC_REGISTER; + register:=NR_X8; end - end; - - hp.paraloc[side].size:=paracgsize; - hp.paraloc[side].Alignment:=std_param_align; - hp.paraloc[side].intsize:=paralen; - hp.paraloc[side].def:=paradef; - firstparaloc:=true; - -{$ifdef EXTDEBUG} - if paralen=0 then - internalerror(200410311); -{$endif EXTDEBUG} - while paralen>0 do - begin - paraloc:=hp.paraloc[side].add_location; - - if (loc=LOC_REGISTER) and (paracgsize in [OS_F32,OS_F64,OS_F80]) then - case paracgsize of - OS_F32: - paraloc^.size:=OS_32; - OS_F64: - paraloc^.size:=OS_32; - else - internalerror(2005082901); - end - else if (paracgsize in [OS_NO,OS_64,OS_S64]) then - paraloc^.size := OS_32 - else - paraloc^.size:=paracgsize; - case loc of - LOC_REGISTER: - begin - { align registers for eabi } - if (target_info.abi in [abi_eabi,abi_eabihf]) and - firstparaloc and - (paradef.alignment=8) then - begin - if (nextintreg in [RS_R1,RS_R3]) then - inc(nextintreg) - else if nextintreg>RS_R3 then - stack_offset:=align(stack_offset,8); - end; - { this is not abi compliant - why? (FK) } - if nextintreg<=RS_R3 then - begin - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=newreg(R_INTREGISTER,nextintreg,R_SUBWHOLE); - inc(nextintreg); - end - else - begin - { LOC_REFERENCE always contains everything that's left } - paraloc^.loc:=LOC_REFERENCE; - paraloc^.size:=int_cgsize(paralen); - if (side=callerside) then - paraloc^.reference.index:=NR_STACK_POINTER_REG; - paraloc^.reference.offset:=stack_offset; - inc(stack_offset,align(paralen,4)); - paralen:=0; - end; - end; - LOC_FPUREGISTER: - begin - if nextfloatreg<=RS_F3 then - begin - paraloc^.loc:=LOC_FPUREGISTER; - paraloc^.register:=newreg(R_FPUREGISTER,nextfloatreg,R_SUBWHOLE); - inc(nextfloatreg); - end - else - begin - paraloc^.loc:=LOC_REFERENCE; - paraloc^.reference.index:=NR_STACK_POINTER_REG; - paraloc^.reference.offset:=stack_offset; - case paraloc^.size of - OS_F32: - inc(stack_offset,4); - OS_F64: - inc(stack_offset,8); - OS_F80: - inc(stack_offset,10); - OS_F128: - inc(stack_offset,16); - else - internalerror(200403201); - end; - end; - end; - LOC_MMREGISTER: - begin - if (nextmmreg<=RS_D7) or - ((paraloc^.size = OS_F32) and - (sparesinglereg<>NR_NO)) then - begin - paraloc^.loc:=LOC_MMREGISTER; - case paraloc^.size of - OS_F32: - if sparesinglereg = NR_NO then - begin - paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFS); - sparesinglereg:=newreg(R_MMREGISTER,nextmmreg-RS_S0+RS_S1,R_SUBFS); - inc(nextmmreg); - end - else - begin - paraloc^.register:=sparesinglereg; - sparesinglereg := NR_NO; - end; - OS_F64: - begin - paraloc^.register:=newreg(R_MMREGISTER,nextmmreg,R_SUBFD); - inc(nextmmreg); - end; - else - internalerror(2012031601); - end; - end - else - begin - { once a floating point parameters has been placed - on the stack we must not pass any more in vfp regs - even if there is a single precision register still - free} - sparesinglereg := NR_NO; - { LOC_REFERENCE always contains everything that's left } - paraloc^.loc:=LOC_REFERENCE; - paraloc^.size:=int_cgsize(paralen); - if (side=callerside) then - paraloc^.reference.index:=NR_STACK_POINTER_REG; - paraloc^.reference.offset:=stack_offset; - inc(stack_offset,align(paralen,4)); - paralen:=0; - end; - end; - LOC_REFERENCE: - begin - if push_addr_param(hp.varspez,paradef,p.proccalloption) then - begin - paraloc^.size:=OS_ADDR; - assignintreg - end - else - begin - { align stack for eabi } - if (target_info.abi in [abi_eabi,abi_eabihf]) and - firstparaloc and - (paradef.alignment=8) then - stack_offset:=align(stack_offset,8); - - paraloc^.size:=paracgsize; - paraloc^.loc:=LOC_REFERENCE; - paraloc^.reference.index:=NR_STACK_POINTER_REG; - paraloc^.reference.offset:=stack_offset; - inc(stack_offset,align(paralen,4)); - paralen:=0 - end; - end; - else - internalerror(2002071002); - end; - if side=calleeside then - begin - if paraloc^.loc=LOC_REFERENCE then - begin - paraloc^.reference.index:=NR_FRAME_POINTER_REG; - { on non-Darwin, the framepointer contains the value - of the stack pointer on entry. On Darwin, the - framepointer points to the previously saved - framepointer (which is followed only by the saved - return address -> framepointer + 4 = stack pointer - on entry } - if not(target_info.system in systems_darwin) then - inc(paraloc^.reference.offset,4) - else - inc(paraloc^.reference.offset,8); - end; - end; - dec(paralen,tcgsize2size[paraloc^.size]); - firstparaloc:=false - end; + end + else + alloc_para(hp.paraloc[side],p,hp.varspez,side,hp.vardef,isvariadic, + (vo_is_parentfp in hp.varoptions) and + (po_delphi_nested_cc in p.procoptions)); end; - curintreg:=nextintreg; - curfloatreg:=nextfloatreg; - curmmreg:=nextmmreg; - cur_stack_offset:=stack_offset; - result:=cur_stack_offset; end; function taarch64paramanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara; var - paraloc : pcgparalocation; - retcgsize : tcgsize; + 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 + { in this case, it must be returned in registers as if it were passed + as the first parameter } + init_para_alloc_values; + alloc_para(result,p,vs_value,side,result.def,false,false); + { sanity check (LOC_VOID for empty records) } + if not assigned(result.location) or + not(result.location^.loc in [LOC_REGISTER,LOC_MMREGISTER,LOC_VOID]) then + internalerror(2014113001); + end; + + function taarch64paramanager.param_use_paraloc(const cgpara: tcgpara): boolean; + begin + { we always set up a stack frame -> we can always access the parameters + this way } + result:= + (cgpara.location^.loc=LOC_REFERENCE) and + not assigned(cgpara.location^.next); + end; + + + procedure taarch64paramanager.init_para_alloc_values; + begin + curintreg:=RS_FIRST_INT_PARAM_SUPREG; + curmmreg:=RS_FIRST_MM_PARAM_SUPREG; + curstackoffset:=0; + end; + + + procedure taarch64paramanager.alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean); + var + hfabasedef, locdef: tdef; + paraloc: pcgparalocation; + paralen, stackslotlen: asizeint; + loc: tcgloc; + paracgsize, locsize: tcgsize; + firstparaloc: boolean; + begin + result.reset; + + { currently only support C-style array of const, + there should be no location assigned to the vararg array itself } + if (p.proccalloption in cstylearrayofconst) and + is_array_of_const(paradef) then begin - if target_info.abi = abi_eabihf then - begin - paraloc^.loc:=LOC_MMREGISTER; - case retcgsize of - OS_64, - OS_F64: - begin - paraloc^.register:=NR_MM_RESULT_REG; - end; - OS_32, - OS_F32: - begin - paraloc^.register:=NR_S0; - end; - else - internalerror(2012032501); - end; - paraloc^.size:=retcgsize; - end - else if (p.proccalloption in [pocall_softfloat]) or - (cs_fp_emulation in current_settings.moduleswitches) or - (current_settings.fputype in [fpu_vfpv2,fpu_vfpv3,fpu_vfpv3_d16,fpu_fpv4_s16]) then - begin - case retcgsize of - OS_64, - OS_F64: - begin - paraloc^.loc:=LOC_REGISTER; - if target_info.endian = endian_big then - paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG - else - paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG; - paraloc^.size:=OS_32; - paraloc:=result.add_location; - paraloc^.loc:=LOC_REGISTER; - if target_info.endian = endian_big then - paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG - else - paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG; - paraloc^.size:=OS_32; - end; - OS_32, - OS_F32: - begin - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=NR_FUNCTION_RETURN_REG; - paraloc^.size:=OS_32; - end; - else - internalerror(2005082603); - end; - end - else - begin - paraloc^.loc:=LOC_FPUREGISTER; - paraloc^.register:=NR_FPU_RESULT_REG; - paraloc^.size:=retcgsize; - end; + paraloc:=result.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; + exit; + end; + + if push_addr_param(varspez,paradef,p.proccalloption) then + begin + paradef:=getpointerdef(paradef); + loc:=LOC_REGISTER; + paracgsize:=OS_ADDR; + paralen:=tcgsize2size[OS_ADDR]; end - { Return in register } else begin - if retcgsize in [OS_64,OS_S64] then - begin - paraloc^.loc:=LOC_REGISTER; - if target_info.endian = endian_big then - paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG - else - paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG; - paraloc^.size:=OS_32; - paraloc:=result.add_location; - paraloc^.loc:=LOC_REGISTER; - if target_info.endian = endian_big then - paraloc^.register:=NR_FUNCTION_RESULT64_LOW_REG - else - paraloc^.register:=NR_FUNCTION_RESULT64_HIGH_REG; - paraloc^.size:=OS_32; - end + if not is_special_array(paradef) then + paralen:=paradef.size + else + paralen:=tcgsize2size[def_cgsize(paradef)]; + loc:=getparaloc(p.proccalloption,paradef); + if (paradef.typ in [objectdef,arraydef,recorddef]) and + not is_special_array(paradef) and + (varspez in [vs_value,vs_const]) then + paracgsize:=int_cgsize(paralen) else begin - paraloc^.loc:=LOC_REGISTER; - paraloc^.register:=NR_FUNCTION_RETURN_REG; - if (result.intsize<>3) then - paraloc^.size:=retcgsize - else - paraloc^.size:=OS_32; - end; + paracgsize:=def_cgsize(paradef); + { for things like formaldef } + if paracgsize=OS_NO then + begin + paracgsize:=OS_ADDR; + paralen:=tcgsize2size[OS_ADDR]; + paradef:=voidpointertype; + end; + end end; + + { get hfa basedef if applicable } + if not is_hfa(paradef,hfabasedef) then + hfabasedef:=nil; + + result.size:=paracgsize; + result.alignment:=std_param_align; + result.intsize:=paralen; + result.def:=paradef; + + { empty record: skipped (explicitly defined by Apple ABI, undefined + by general ABI; libffi also skips them in all cases) } + if not is_special_array(paradef) and + (paradef.size=0) then + begin + paraloc:=result.add_location; + paraloc^.loc:=LOC_VOID; + paraloc^.def:=paradef; + paraloc^.size:=OS_NO; + exit; + end; + + { sufficient registers left? } + case loc of + LOC_REGISTER: + begin + { In case of po_delphi_nested_cc, the parent frame pointer + is always passed on the stack. } + if isdelphinestedcc then + loc:=LOC_REFERENCE + else if curintreg+((paralen-1) shr 3)>RS_LAST_INT_PARAM_SUPREG then + begin + { not enough integer registers left -> no more register + parameters, copy all to stack + } + curintreg:=succ(RS_LAST_INT_PARAM_SUPREG); + loc:=LOC_REFERENCE; + end; + end; + LOC_MMREGISTER: + begin; + { every hfa element must be passed in a separate register } + if (assigned(hfabasedef) and + (curmmreg+(paralen div hfabasedef.size)>RS_LAST_MM_PARAM_SUPREG)) or + (curmmreg+((paralen-1) shr 3)>RS_LAST_MM_PARAM_SUPREG) then + begin + { not enough mm registers left -> no more register + parameters, copy all to stack + } + curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG); + loc:=LOC_REFERENCE; + end; + end; + end; + + { allocate registers/stack locations } + firstparaloc:=true; + repeat + paraloc:=result.add_location; + + { set paraloc size/def } + if assigned(hfabasedef) then + begin + locsize:=def_cgsize(hfabasedef); + locdef:=hfabasedef; + end + { make sure we don't lose whether or not the type is signed } + else if (loc=LOC_REGISTER) and + (paradef.typ<>orddef) then + begin + locsize:=int_cgsize(paralen); + locdef:=get_paraloc_def(paradef,paralen,firstparaloc); + end + else + begin + locsize:=paracgsize; + locdef:=paradef; + end; + if locsize in [OS_NO,OS_128,OS_S128] then + begin + if paralen>4 then + begin + paraloc^.size:=OS_INT; + paraloc^.def:=u64inttype; + end + else + begin + { for 3-byte records } + paraloc^.size:=OS_32; + paraloc^.def:=u32inttype; + end; + end + else + begin + paraloc^.size:=locsize; + paraloc^.def:=locdef; + end; + + { paraloc loc } + paraloc^.loc:=loc; + + { assign register/stack address } + case loc of + LOC_REGISTER: + begin + paraloc^.register:=newreg(R_INTREGISTER,curintreg,cgsize2subreg(R_INTREGISTER,paraloc^.size)); + inc(curintreg); + dec(paralen,tcgsize2size[paraloc^.size]); + + { "The general ABI specifies that it is the callee's + responsibility to sign or zero-extend arguments having fewer + than 32 bits, and that unused bits in a register are + unspecified. In iOS, however, the caller must perform such + extensions, up to 32 bits." } + if (target_info.abi=abi_aarch64_darwin) and + (side=callerside) and + is_ordinal(paradef) and + (paradef.size<4) then + paraloc^.size:=OS_32; + + { in case it's a composite, "The argument is passed as though + it had been loaded into the registers from a double-word- + aligned address with an appropriate sequence of LDR + instructions loading consecutive registers from memory" -> + in case of big endian, values in not completely filled + registers must be shifted to the top bits } + if (target_info.endian=endian_big) and + not(paraloc^.size in [OS_64,OS_S64]) and + (paradef.typ in [setdef,recorddef,arraydef,objectdef]) then + paraloc^.shiftval:=-(8-tcgsize2size[paraloc^.size]); + end; + LOC_MMREGISTER: + begin + paraloc^.register:=newreg(R_MMREGISTER,curmmreg,cgsize2subreg(R_MMREGISTER,paraloc^.size)); + inc(curmmreg); + dec(paralen,tcgsize2size[paraloc^.size]); + end; + LOC_REFERENCE: + begin + paraloc^.size:=paracgsize; + paraloc^.loc:=LOC_REFERENCE; + + { the current stack offset may not be properly aligned in + case we're on Darwin have allocated a non-variadic argument + < 8 bytes previously } + if target_info.abi=abi_aarch64_darwin then + curstackoffset:=align(curstackoffset,paraloc^.def.alignment); + + { on Darwin, non-variadic arguments take up their actual size + on the stack; on other platforms, they take up a multiple of + 8 bytes } + if (target_info.abi=abi_aarch64_darwin) and + not isvariadic then + stackslotlen:=paralen + else + stackslotlen:=align(paralen,8); + + { from the ABI: if arguments occupy partial stack space, they + have to occupy the lowest significant bits of a register + containing that value which is then stored to memory -> + in case of big endian, skip the alignment bytes (if any) } + if target_info.endian=endian_little then + paraloc^.reference.offset:=curstackoffset + else + paraloc^.reference.offset:=curstackoffset+stackslotlen-paralen; + if side=callerside then + paraloc^.reference.index:=NR_STACK_POINTER_REG + else + begin + paraloc^.reference.index:=NR_FRAME_POINTER_REG; + inc(paraloc^.reference.offset,16); + end; + inc(curstackoffset,stackslotlen); + paralen:=0 + end; + else + internalerror(2002071002); + end; + firstparaloc:=false; + { <=0 for sign/zero-extended locations } + until paralen<=0; end; - function taarch64paramanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint; - var - cur_stack_offset: aword; - curintreg, curfloatreg, curmmreg: tsuperregister; - sparesinglereg:tregister; + function taarch64paramanager.create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint; begin - init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg); + init_para_alloc_values; - result:=create_paraloc_info_intern(p,side,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,false); + create_paraloc_info_intern(p,side,p.paras,false); + result:=curstackoffset; create_funcretloc_info(p,side); end; - function taarch64paramanager.create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint; - var - cur_stack_offset: aword; - curintreg, curfloatreg, curmmreg: tsuperregister; - sparesinglereg:tregister; + function taarch64paramanager.create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint; begin - init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg); + init_para_alloc_values; - result:=create_paraloc_info_intern(p,callerside,p.paras,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true); - if (p.proccalloption in cstylearrayofconst) then - { just continue loading the parameters in the registers } - result:=create_paraloc_info_intern(p,callerside,varargspara,curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg,true) + { non-variadic parameters } + create_paraloc_info_intern(p,callerside,p.paras,false); + if p.proccalloption in cstylearrayofconst then + begin + { on Darwin, we cannot use any registers for variadic parameters } + if target_info.abi=abi_aarch64_darwin then + begin + curintreg:=succ(RS_LAST_INT_PARAM_SUPREG); + curmmreg:=succ(RS_LAST_MM_PARAM_SUPREG); + end; + { continue loading the parameters } + create_paraloc_info_intern(p,callerside,varargspara,true); + result:=curstackoffset; + end else internalerror(200410231); end; diff --git a/fpcsrc/compiler/aarch64/cpupi.pas b/fpcsrc/compiler/aarch64/cpupi.pas new file mode 100644 index 00000000..ff6505c4 --- /dev/null +++ b/fpcsrc/compiler/aarch64/cpupi.pas @@ -0,0 +1,68 @@ +{ + 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. + + **************************************************************************** +} +unit cpupi; + +{$i fpcdefs.inc} + +interface + + uses + procinfo, + psub; + + type + taarch64procinfo=class(tcgprocinfo) + constructor create(aparent: tprocinfo); override; + procedure set_first_temp_offset; override; + end; + +implementation + + uses + tgobj, + cpubase; + + constructor taarch64procinfo.create(aparent: tprocinfo); + begin + inherited; + { use the stack pointer as framepointer, because + 1) we exactly know the offsets of the temps from the stack pointer + after pass 1 (based on the require parameter stack size for called + routines), while we don't know it for the frame pointer (it depends + on the number of saved registers) + 2) temp offsets from the stack pointer are positive while those from + the frame pointer are negative, and we can directly encode much + bigger positive offsets in the instructions + } + framepointer:=NR_STACK_POINTER_REG; + end; + + procedure taarch64procinfo.set_first_temp_offset; + begin + { leave room for allocated parameters } + tg.setfirsttemp(align(maxpushedparasize,16)); + end; + + +begin + cprocinfo:=taarch64procinfo; +end. diff --git a/fpcsrc/compiler/aarch64/cputarg.pas b/fpcsrc/compiler/aarch64/cputarg.pas new file mode 100644 index 00000000..584a295c --- /dev/null +++ b/fpcsrc/compiler/aarch64/cputarg.pas @@ -0,0 +1,70 @@ +{ + Copyright (c) 2001-2002 by Peter Vreman + + Includes the AArch64 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 NOTARGETBSD} + ,t_bsd + {$endif} + +{************************************** + Assemblers +**************************************} + + {$ifndef NOAGCPUGAS} + ,agcpugas + {$endif} + +{************************************** + Assembler Readers +**************************************} + + {$ifndef NoRaarmgas} + ,racpugas + {$endif NoRaarmgas} + +{************************************** + Debuginfo +**************************************} + + {$ifndef NoDbgDwarf} + ,dbgdwarf + {$endif NoDbgDwarf} + ; + +end. diff --git a/fpcsrc/compiler/aarch64/hlcgcpu.pas b/fpcsrc/compiler/aarch64/hlcgcpu.pas new file mode 100644 index 00000000..bdcecce0 --- /dev/null +++ b/fpcsrc/compiler/aarch64/hlcgcpu.pas @@ -0,0 +1,156 @@ +{ + Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe + Member of the Free Pascal development team + + This unit contains routines to create a pass-through high-level code + generator. This is used by most regular code generators. + + 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 + symtype, + aasmdata, + cgbase,cgutils, + hlcgobj, hlcg2ll; + + type + thlcgaarch64 = class(thlcg2ll) + procedure a_load_subsetreg_reg(list: TAsmList; subsetsize, tosize: tdef; const sreg: tsubsetregister; destreg: tregister); override; + procedure a_load_subsetreg_subsetreg(list: TAsmlist; fromsubsetsize, tosubsetsize: tdef; const fromsreg, tosreg: tsubsetregister); override; + protected + procedure a_load_regconst_subsetreg_intern(list: TAsmList; fromsize, subsetsize: tdef; fromreg: tregister; const sreg: tsubsetregister; slopt: tsubsetloadopt); override; + end; + + procedure create_hlcodegen; + +implementation + + uses + defutil, + cpubase,aasmcpu, + cgobj,cgcpu; + + procedure thlcgaarch64.a_load_subsetreg_reg(list: TAsmList; subsetsize, tosize: tdef; const sreg: tsubsetregister; destreg: tregister); + var + op: tasmop; + tocgsize: tcgsize; + tmpdestreg: tregister; + begin + tocgsize:=def_cgsize(tosize); + if (sreg.startbit<>0) or + not(sreg.bitlen in [32,64]) then + begin + if is_signed(subsetsize) then + op:=A_SBFX + else + op:=A_UBFX; + { source and destination register of SBFX/UBFX have to be the same size } + if (sreg.subsetregsize in [OS_64,OS_S64]) and + not(tocgsize in [OS_64,OS_S64]) then + tmpdestreg:=cg.getintregister(list,OS_64) + else if not(sreg.subsetregsize in [OS_64,OS_S64]) and + (tocgsize in [OS_64,OS_S64]) then + tmpdestreg:=cg.getintregister(list,OS_32) + else + tmpdestreg:=destreg; + list.concat(taicpu.op_reg_reg_const_const(op,tmpdestreg,sreg.subsetreg,sreg.startbit,sreg.bitlen)); + { need to sign extend further or truncate? } + if (sreg.subsetregsize=OS_S64) and + not(tocgsize in [OS_64,OS_S64]) then + cg.a_load_reg_reg(list,OS_S64,tocgsize,tmpdestreg,destreg) + else if is_signed(subsetsize) and + (tocgsize in [OS_8,OS_16]) then + cg.a_load_reg_reg(list,OS_32,tocgsize,tmpdestreg,destreg) + else if tmpdestreg<>destreg then + cg.a_load_reg_reg(list,def_cgsize(subsetsize),tocgsize,tmpdestreg,destreg) + end + else + cg.a_load_reg_reg(list,def_cgsize(subsetsize),tocgsize,sreg.subsetreg,destreg); + end; + + + procedure makeregssamesize(list: tasmlist; fromsize, tosize: tcgsize; orgfromreg, orgtoreg: tregister; out newfromreg, newtoreg: tregister); + begin + if (fromsize in [OS_S64,OS_64])<> + (tosize in [OS_S64,OS_64]) then + begin + newfromreg:=cg.makeregsize(list,orgfromreg,OS_64); + newtoreg:=cg.makeregsize(list,orgtoreg,OS_64); + end + else + begin + newfromreg:=orgfromreg; + newtoreg:=orgtoreg; + end; + end; + + + procedure thlcgaarch64.a_load_subsetreg_subsetreg(list: TAsmlist; fromsubsetsize, tosubsetsize: tdef; const fromsreg, tosreg: tsubsetregister); + var + fromreg, toreg: tregister; + + begin + { BFM can only insert a bitfield that starts at position 0 in the source + source or destination register } + if (tosreg.startbit=0) and + (fromsreg.bitlen>=tosreg.bitlen) then + begin + makeregssamesize(list,fromsreg.subsetregsize,tosreg.subsetregsize,fromsreg.subsetreg,tosreg.subsetreg,fromreg,toreg); + list.concat(taicpu.op_reg_reg_const_const(A_BFXIL,toreg,fromreg,fromsreg.startbit,tosreg.bitlen)) + end + else if (fromsreg.startbit=0) and + (fromsreg.bitlen>=tosreg.bitlen) then + begin + makeregssamesize(list,fromsreg.subsetregsize,tosreg.subsetregsize,fromsreg.subsetreg,tosreg.subsetreg,fromreg,toreg); + list.concat(taicpu.op_reg_reg_const_const(A_BFI,toreg,fromreg,tosreg.startbit,tosreg.bitlen)) + end + else + inherited; + end; + + + procedure thlcgaarch64.a_load_regconst_subsetreg_intern(list: TAsmList; fromsize, subsetsize: tdef; fromreg: tregister; const sreg: tsubsetregister; slopt: tsubsetloadopt); + var + toreg: tregister; + begin + if slopt in [SL_SETZERO,SL_SETMAX] then + inherited + else if not(sreg.bitlen in [32,64]) then + begin + makeregssamesize(list,def_cgsize(fromsize),sreg.subsetregsize,fromreg,sreg.subsetreg,fromreg,toreg); + list.concat(taicpu.op_reg_reg_const_const(A_BFI,toreg,fromreg,sreg.startbit,sreg.bitlen)) + end + else + a_load_reg_reg(list,fromsize,subsetsize,fromreg,sreg.subsetreg); + end; + + + procedure create_hlcodegen; + begin + hlcg:=thlcgaarch64.create; + create_codegen; + end; + + +end. diff --git a/fpcsrc/compiler/aarch64/ncpuadd.pas b/fpcsrc/compiler/aarch64/ncpuadd.pas new file mode 100644 index 00000000..16c9abcb --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpuadd.pas @@ -0,0 +1,402 @@ +{ + Copyright (c) 2014 Jonas Maebe + + Code generation for add nodes on AArch64 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit ncpuadd; + +{$i fpcdefs.inc} + +interface + + uses + node,ncgadd,cpubase; + + type + taarch64addnode = class(tcgaddnode) + private + function GetResFlags(unsigned:Boolean):TResFlags; + function GetFPUResFlags:TResFlags; + protected + procedure second_addfloat;override; + procedure second_cmpfloat;override; + procedure second_cmpboolean;override; + procedure second_cmpsmallset;override; + procedure second_cmpordinal;override; + procedure second_addordinal;override; + procedure second_add64bit; override; + procedure second_cmp64bit; override; + public + function use_generic_mul32to64: boolean; override; + end; + + implementation + + uses + systems, + cutils,verbose, + paramgr,procinfo, + aasmtai,aasmdata,aasmcpu,defutil, + cgbase,cgcpu,cgutils, + cpupara, + ncon,nset,nadd, + hlcgobj, ncgutil,cgobj; + +{***************************************************************************** + taarch64addnode +*****************************************************************************} + + function taarch64addnode.GetResFlags(unsigned:Boolean):TResFlags; + begin + case NodeType of + equaln: + GetResFlags:=F_EQ; + unequaln: + GetResFlags:=F_NE; + else + if not(unsigned) then + begin + if nf_swapped in flags then + case NodeType of + ltn: + GetResFlags:=F_GT; + lten: + GetResFlags:=F_GE; + gtn: + GetResFlags:=F_LT; + gten: + GetResFlags:=F_LE; + else + internalerror(2014082010); + end + else + case NodeType of + ltn: + GetResFlags:=F_LT; + lten: + GetResFlags:=F_LE; + gtn: + GetResFlags:=F_GT; + gten: + GetResFlags:=F_GE; + else + internalerror(2014082011); + end; + end + else + begin + if nf_swapped in Flags then + case NodeType of + ltn: + GetResFlags:=F_HI; + lten: + GetResFlags:=F_HS; + gtn: + GetResFlags:=F_LO; + gten: + GetResFlags:=F_LS; + else + internalerror(2014082012); + end + else + case NodeType of + ltn: + GetResFlags:=F_LO; + lten: + GetResFlags:=F_LS; + gtn: + GetResFlags:=F_HI; + gten: + GetResFlags:=F_HS; + else + internalerror(2014082013); + end; + end; + end; + end; + + + function taarch64addnode.GetFPUResFlags:TResFlags; + begin + case NodeType of + equaln: + result:=F_EQ; + unequaln: + result:=F_NE; + else + begin + if nf_swapped in Flags then + case NodeType of + ltn: + result:=F_GT; + lten: + result:=F_GE; + gtn: + result:=F_LO; + gten: + result:=F_LS; + else + internalerror(2014082014); + end + else + case NodeType of + ltn: + result:=F_LO; + lten: + result:=F_LS; + gtn: + result:=F_GT; + gten: + result:=F_GE; + else + internalerror(2014082015); + end; + end; + end; + end; + + + procedure taarch64addnode.second_addfloat; + var + op : TAsmOp; + begin + pass_left_right; + if nf_swapped in flags then + swapleftright; + + { force fpureg as location, left right doesn't matter + as both will be in a fpureg } + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,right.resultdef,true); + + location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef)); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + + case nodetype of + addn : + begin + op:=A_FADD; + end; + muln : + begin + op:=A_FMUL; + end; + subn : + begin + op:=A_FSUB; + end; + slashn : + begin + op:=A_FDIV; + end; + else + internalerror(200306014); + end; + + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, + location.register,left.location.register,right.location.register)); + end; + + + procedure taarch64addnode.second_cmpfloat; + begin + pass_left_right; + if nf_swapped in flags then + swapleftright; + + { force fpureg as location, left right doesn't matter + as both will be in a fpureg } + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,right.resultdef,true); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getfpuresflags; + + { signalling compare so we can get exceptions } + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCMPE, + left.location.register,right.location.register)); + end; + + + procedure taarch64addnode.second_cmpboolean; + begin + pass_left_right; + force_reg_left_right(true,true); + + if right.location.loc=LOC_CONSTANT then + begin + if right.location.value>=0 then + Tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,A_CMP,left.location.size,left.location.register,right.location.value,NR_XZR,NR_NO,false,false) + else + { avoid overflow if value=low(int64) } +{$push}{$r-}{$q-} + Tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,A_CMN,left.location.size,left.location.register,-right.location.value,NR_XZR,NR_NO,false,false) +{$pop} + end + else + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,left.location.register,right.location.register)); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(true); + end; + + + procedure taarch64addnode.second_cmpsmallset; + var + tmpreg : tregister; + op: tasmop; + begin + pass_left_right; + + location_reset(location,LOC_FLAGS,OS_NO); + + force_reg_left_right(true,true); + + if right.location.loc=LOC_CONSTANT then + begin + { when doing a cmp/cmn on 32 bit, we care whether the *lower 32 bit* + is a positive/negative value -> sign extend } + if not(right.location.size in [OS_64,OS_S64]) then + right.location.value:=longint(right.location.value); + if right.location.value>=0 then + op:=A_CMP + else + op:=A_CMN; + end + else + { for DFA } + op:=A_NONE; + + case nodetype of + equaln, + unequaln: + begin + if right.location.loc=LOC_CONSTANT then + tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,op,def_cgsize(resultdef),left.location.register,abs(right.location.value),NR_XZR,NR_NO,false,false) + else + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,left.location.register,right.location.register)); + location.resflags:=getresflags(true); + end; + lten, + gten: + begin + if (not(nf_swapped in flags) and + (nodetype=lten)) or + ((nf_swapped in flags) and + (nodetype=gten)) then + swapleftright; + { we can't handle left as a constant yet } + if left.location.loc=LOC_CONSTANT then + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + tmpreg:=cg.getintregister(current_asmdata.CurrAsmList,left.location.size); + if right.location.loc=LOC_CONSTANT then + begin + hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_AND,resultdef,right.location.value,left.location.register,tmpreg); + tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,op,def_cgsize(resultdef),tmpreg,abs(right.location.value),NR_XZR,NR_NO,false,false) + end + else + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_AND,tmpreg,left.location.register,right.location.register)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,tmpreg,right.location.register)); + end; + location.resflags:=F_EQ; + end; + else + internalerror(2012042701); + end; + end; + + + procedure taarch64addnode.second_cmpordinal; + var + unsigned : boolean; + begin + pass_left_right; + force_reg_left_right(true,true); + + unsigned:=not(is_signed(left.resultdef)) or + not(is_signed(right.resultdef)); + + if right.location.loc = LOC_CONSTANT then + begin + if right.location.value>=0 then + Tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,A_CMP,left.location.size,left.location.register,right.location.value,NR_XZR,NR_NO,false,false) + else +{$push}{$r-}{$q-} + Tcgaarch64(cg).handle_reg_imm12_reg(current_asmdata.CurrAsmList,A_CMN,left.location.size,left.location.register,-right.location.value,NR_XZR,NR_NO,false,false) +{$pop} + end + else + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_CMP,left.location.register,right.location.register)); + + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=getresflags(unsigned); + end; + + + procedure taarch64addnode.second_addordinal; + const + multops: array[boolean] of TAsmOp = (A_SMULL,A_UMULL); + var + unsigned: boolean; + begin + { 32x32->64 multiplication } + if (nodetype=muln) and + is_32bit(left.resultdef) and + is_32bit(right.resultdef) and + is_64bit(resultdef) then + begin + unsigned:=not(is_signed(left.resultdef)) or + not(is_signed(right.resultdef)); + pass_left_right; + force_reg_left_right(true,true); + { force_reg_left_right can leave right as a LOC_CONSTANT (we can't + say "a constant register is okay, but an ordinal constant isn't) } + if right.location.loc=LOC_CONSTANT then + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); + location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); + location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef)); + current_asmdata.CurrAsmList.Concat(taicpu.op_reg_reg_reg(multops[unsigned],location.register,left.location.register,right.location.register)); + end + else + inherited second_addordinal; + end; + + + procedure taarch64addnode.second_add64bit; + begin + second_addordinal; + end; + + + procedure taarch64addnode.second_cmp64bit; + begin + second_cmpordinal; + end; + + + function taarch64addnode.use_generic_mul32to64: boolean; + begin + result:=false; + end; + + +begin + caddnode:=taarch64addnode; +end. diff --git a/fpcsrc/compiler/aarch64/ncpucnv.pas b/fpcsrc/compiler/aarch64/ncpucnv.pas new file mode 100644 index 00000000..459d47a7 --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpucnv.pas @@ -0,0 +1,201 @@ +{ + Copyright (c) 2014 by Jonas Maebe + + Generate AArch64 assembler for type converting nodes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + ****************************************************************************} +unit ncpucnv; + +{$i fpcdefs.inc} + +interface + + uses + node,ncnv,ncgcnv; + + type + taarch64typeconvnode = class(TCgTypeConvNode) + protected + function typecheck_int_to_real: tnode; override; + function first_int_to_real: tnode; override; + + { 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; } + { 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,globals, + symdef,aasmdata,aasmbase, + defutil, + cgbase,cgutils,procinfo, + cpubase,aasmcpu, + pass_2,cgobj, + hlcgobj; + + +{***************************************************************************** + FirstTypeConv +*****************************************************************************} + + function taarch64typeconvnode.typecheck_int_to_real: tnode; + begin + { aarch64 supports converting everything to floating point, even fixed + point! Unfortunately, it only supports fixed point with a power-of-2 + fraction, which is not the case for currency. + + Generate the division by 10000 via nodes so the 10000.0 constant can + be reused. } + if is_currency(resultdef) and + not(nf_is_currency in flags) then + begin + { convert the equivalent int64 value to double without conversion + (internal typecast -> will set nf_is_currency flag) } + result:=ctypeconvnode.create_internal(left,s64floattype); + { turn into currency with conversion, which will divide by 10000 + (regular typecast) } + result:=ctypeconvnode.create(result,s64currencytype); + exit; + end; + { The only other thing we have to take care of: convert values < 32 bit + to 32 bit } + if left.resultdef.size<4 then + begin + if is_signed(left.resultdef) then + inserttypeconv(left,s32inttype) + else + inserttypeconv(left,u32inttype) + end; + result:=inherited; + end; + + + function taarch64typeconvnode.first_int_to_real: tnode; + begin + result:=nil; + expectloc:=LOC_MMREGISTER; + end; + + +{***************************************************************************** + SecondTypeConv +*****************************************************************************} + + procedure taarch64typeconvnode.second_int_to_real; + var + op: tasmop; + begin + location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef)); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then + internalerror(2014120401); + case left.location.size of + OS_32, + OS_64: + op:=A_UCVTF; + OS_S32, + OS_S64, + { for currency and comp } + OS_F64: + op:=A_SCVTF; + else + internalerror(2014120402); + end; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register)); + { no scaling for currency, that's handled in pass_typecheck } + end; + + + procedure taarch64typeconvnode.second_int_to_bool; + var + resflags: tresflags; + hlabel,oldTrueLabel,oldFalseLabel : tasmlabel; + begin + if (nf_explicit in flags) and + not(left.expectloc in [LOC_FLAGS,LOC_JUMP]) then + begin + inherited; + exit; + end; + + { can't use the generic code, as it assumes that OP_OR automatically sets + the flags. We can also do things more efficiently directly } + + oldTrueLabel:=current_procinfo.CurrTrueLabel; + oldFalseLabel:=current_procinfo.CurrFalseLabel; + current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel); + current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel); + secondpass(left); + if codegenerror then + exit; + + case left.location.loc of + LOC_CREFERENCE, + LOC_REFERENCE, + LOC_REGISTER, + LOC_CREGISTER, + LOC_JUMP: + begin + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,left.location.register,0)); + resflags:=F_NE; + end; + LOC_FLAGS : + resflags:=left.location.resflags; + else + internalerror(2014122902); + end; + { load flags to register } + location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); + location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size); + if is_cbool(resultdef) then + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_cond(A_CSETM,location.register,flags_to_cond(resflags))); + { truncate? (in case cbools are ever made unsigned) } + if resultdef.size<4 then + cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,location.size,location.register,location.register); + end + else + cg.g_flags2reg(current_asmdata.CurrAsmList,location.size,resflags,location.register); + cg.a_reg_dealloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS); + current_procinfo.CurrTrueLabel:=oldTrueLabel; + current_procinfo.CurrFalseLabel:=oldFalseLabel; + end; + + +begin + ctypeconvnode:=taarch64typeconvnode; +end. diff --git a/fpcsrc/compiler/aarch64/ncpuinl.pas b/fpcsrc/compiler/aarch64/ncpuinl.pas new file mode 100644 index 00000000..93f3456d --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpuinl.pas @@ -0,0 +1,184 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + Generates ARM inline nodes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit ncpuinl; + +{$i fpcdefs.inc} + +interface + + uses + node,ninl,ncginl; + + type + taarch64inlinenode = class(tcgInlineNode) + function first_abs_real: tnode; override; + function first_sqr_real: tnode; override; + function first_sqrt_real: tnode; override; + function first_round_real: tnode; override; + function first_trunc_real: tnode; override; + procedure second_abs_real; override; + procedure second_sqr_real; override; + procedure second_sqrt_real; override; + procedure second_abs_long; override; + procedure second_round_real; override; + procedure second_trunc_real; override; + procedure second_get_frame; override; + private + procedure load_fpu_location; + end; + + +implementation + + uses + globtype,verbose,globals, + cpuinfo, defutil,symdef,aasmdata,aasmcpu, + cgbase,cgutils,pass_1,pass_2, + cpubase,ncgutil,cgobj,cgcpu, hlcgobj; + +{***************************************************************************** + taarch64inlinenode +*****************************************************************************} + + procedure taarch64inlinenode.load_fpu_location; + begin + secondpass(left); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + location_copy(location,left.location); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + location.loc:=LOC_MMREGISTER; + end; + + + function taarch64inlinenode.first_abs_real : tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + function taarch64inlinenode.first_sqr_real : tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + function taarch64inlinenode.first_sqrt_real : tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + function taarch64inlinenode.first_round_real: tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + function taarch64inlinenode.first_trunc_real: tnode; + begin + expectloc:=LOC_MMREGISTER; + result:=nil; + end; + + + procedure taarch64inlinenode.second_abs_real; + begin + load_fpu_location; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FABS,location.register,left.location.register)); + end; + + + procedure taarch64inlinenode.second_sqr_real; + begin + load_fpu_location; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_FMUL,location.register,left.location.register,left.location.register)); + end; + + + procedure taarch64inlinenode.second_sqrt_real; + begin + load_fpu_location; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FSQRT,location.register,left.location.register)); + end; + + + procedure taarch64inlinenode.second_abs_long; + var + opsize : tcgsize; + hp : taicpu; + begin + secondpass(left); + opsize:=def_cgsize(left.resultdef); + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + location:=left.location; + location.register:=cg.getintregister(current_asmdata.CurrAsmList,opsize); + + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_NEG,location.register,left.location.register),PF_S)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_cond(A_CSEL,location.register,location.register,left.location.register,C_GE)); + end; + + + procedure taarch64inlinenode.second_round_real; + var + hreg: tregister; + begin + secondpass(left); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); + location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size); + hreg:=cg.getmmregister(current_asmdata.CurrAsmList,left.location.size); + { round as floating point using current rounding mode } + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FRINTX,hreg,left.location.register)); + { convert to signed integer rounding towards zero (there's no "round to + integer using current rounding mode") } + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCVTZS,location.register,hreg)); + end; + + + procedure taarch64inlinenode.second_trunc_real; + begin + secondpass(left); + hlcg.location_force_mmregscalar(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 } + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FCVTZS,location.register,left.location.register)); + end; + + + procedure taarch64inlinenode.second_get_frame; + begin + location_reset(location,LOC_CREGISTER,OS_ADDR); + { this routine is used to get the frame pointer for backtracing + purposes. current_procinfo.framepointer is set to SP because that one + is used to access temps. On most platforms these two frame pointers + are the same, but not on AArch64. } + location.register:=NR_FRAME_POINTER_REG; + end; + +begin + cinlinenode:=taarch64inlinenode; +end. diff --git a/fpcsrc/compiler/aarch64/ncpumat.pas b/fpcsrc/compiler/aarch64/ncpumat.pas new file mode 100644 index 00000000..8837490e --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpumat.pas @@ -0,0 +1,196 @@ +{ + Copyright (c) 1998-2002, 2014 by Florian Klaempfl and Jonas Maebe + + Generate AArch64 assembler for math nodes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit ncpumat; + +{$i fpcdefs.inc} + +interface + + uses + node,nmat,ncgmat; + + type + taarch64moddivnode = class(tmoddivnode) + function pass_1: tnode; override; + procedure pass_generate_code;override; + end; + + taarch64notnode = class(tcgnotnode) + procedure second_boolean;override; + end; + + taarch64unaryminusnode = class(tcgunaryminusnode) + procedure second_float; override; + end; + +implementation + + uses + globtype,systems,constexp, + cutils,verbose,globals, + symconst,symdef, + aasmbase,aasmcpu,aasmtai,aasmdata, + defutil, + cgbase,cgobj,hlcgobj,pass_2,procinfo, + ncon, + cpubase, + ncgutil,cgcpu,cgutils; + +{***************************************************************************** + taarch64moddivnode +*****************************************************************************} + + function taarch64moddivnode.pass_1: tnode; + begin + result:=inherited pass_1; + if not assigned(result) then + include(current_procinfo.flags,pi_do_call); + end; + + + procedure taarch64moddivnode.pass_generate_code; + var + op : tasmop; + tmpreg, + numerator, + divider, + resultreg : tregister; + hl : tasmlabel; + overflowloc: tlocation; + begin + secondpass(left); + secondpass(right); + + { set result location } + location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); + location.register:=cg.getintregister(current_asmdata.CurrAsmList,def_cgsize(resultdef)); + resultreg:=location.register; + + { put numerator in register } + hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,true); + numerator:=left.location.register; + + { load divider in a register } + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,true); + divider:=right.location.register; + + { start division } + if is_signed(left.resultdef) then + op:=A_SDIV + else + op:=A_UDIV; + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,numerator,divider)); + + { no divide-by-zero detection available in hardware, emulate (if it's a + constant, this will have been detected earlier already) } + if (right.nodetype<>ordconstn) then + begin + current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP, + right.location.register,0)); + + current_asmdata.getjumplabel(hl); + current_asmdata.CurrAsmList.concat(taicpu.op_cond_sym(A_B,C_NE,hl)); + cg.a_call_name(current_asmdata.CurrAsmList,'FPC_DIVBYZERO',false); + cg.a_label(current_asmdata.CurrAsmList,hl); + end; + + { in case of overflow checking, also check for low(int64) div (-1) + (no hardware support for this either) } + if (cs_check_overflow in current_settings.localswitches) and + is_signed(left.resultdef) and + ((right.nodetype<>ordconstn) or + (tordconstnode(right).value=-1)) then + begin + { num=ffff... and div=8000... <=> + num xor not(div xor 8000...) = 0 + (and we have the "eon" operation, which performs "xor not(...)" } + tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,left.resultdef); + hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_XOR,left.resultdef,low(int64),left.location.register,tmpreg); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(A_EON, + tmpreg,left.location.register,tmpreg)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP,tmpreg,0)); + { now the zero/equal flag is set in case we divided low(int64) by + (-1) } + location_reset(overflowloc,LOC_FLAGS,OS_NO); + overflowloc.resflags:=F_EQ; + cg.g_overflowcheck_loc(current_asmdata.CurrAsmList,location,resultdef,overflowloc); + end; + + { in case of modulo, multiply result again by the divider and subtract + from the numerator } + if nodetype=modn then + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg_reg(A_MSUB,resultreg, + resultreg,divider,numerator)); + end; + + +{***************************************************************************** + taarch64notnode +*****************************************************************************} + + procedure taarch64notnode.second_boolean; + begin + if not handle_locjump then + begin + secondpass(left); + case left.location.loc of + LOC_FLAGS : + begin + 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,true); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_const(A_CMP, + left.location.register,0)); + location_reset(location,LOC_FLAGS,OS_NO); + location.resflags:=F_EQ; + end; + else + internalerror(2003042401); + end; + end; + end; + + +{***************************************************************************** + taarch64unaryminusnode +*****************************************************************************} + + procedure taarch64unaryminusnode.second_float; + begin + secondpass(left); + hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); + location_reset(location,LOC_MMREGISTER,def_cgsize(resultdef)); + location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_FNEG,location.register,left.location.register)); + end; + +begin + cmoddivnode:=taarch64moddivnode; + cnotnode:=taarch64notnode; + cunaryminusnode:=taarch64unaryminusnode; +end. diff --git a/fpcsrc/compiler/aarch64/ncpumem.pas b/fpcsrc/compiler/aarch64/ncpumem.pas new file mode 100644 index 00000000..99e6f4cf --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpumem.pas @@ -0,0 +1,142 @@ +{ + Copyright (c) 2014 by Jonas Maebe + + Generate AArch64 code for in memory related 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 ncpumem; + +{$i fpcdefs.inc} + +interface + + uses + globtype, + cgbase, + symtype, + node,nmem,ncgmem; + + type + taarch64loadparentfpnode = class(tcgloadparentfpnode) + procedure pass_generate_code; override; + end; + + taarch64vecnode = class(tcgvecnode) + protected + function valid_index_size(size: tcgsize): boolean; override; + public + procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); override; + end; + +implementation + + uses + cutils,verbose, + defutil, + aasmdata,cpubase, + cgutils, + cgobj; + + { taarch64loadparentfpnode } + + procedure taarch64loadparentfpnode.pass_generate_code; + begin + inherited pass_generate_code; + { see the comments in tcgaarch64.g_proc_entry } + if (location.loc in [LOC_REGISTER,LOC_CREGISTER]) and + (location.register=NR_STACK_POINTER_REG) then + if (kind=lpf_forpara) then + location.register:=NR_FRAME_POINTER_REG + else + begin + { load stack pointer in a different register, as many instructions + cannot directly work with the stack pointer. The register + allocator can merge them if possible } + location.register:=cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,NR_STACK_POINTER_REG,location.register); + location.loc:=LOC_REGISTER; + end; + end; + + + { taarch64vecnode } + + function taarch64vecnode.valid_index_size(size: tcgsize): boolean; + begin + { all sizes are ok if we handle the "reference reg mul", because + a) we use a 64 bit register for 64 bit values, and a 32 bit one (that + we can sign/zero-extend inside the reference) for smaller values + b) for values < 32 bit, the entire 32 bit register always contains the + sign/zero-extended version of the value } + result:= + not is_packed_array(left.resultdef) and + (get_mul_size in [1,2,4,8,16]); + end; + + + procedure taarch64vecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); + var + base: tregister; + oldoffset: asizeint; + shift: byte; + begin + { we can only scale the index by shl 0..4 } + if not(l in [1,2,4,8,16]) then + begin + inherited; + exit; + end; + { we need a base set and an index available } + if (location.reference.base=NR_NO) or + (location.reference.index<>NR_NO) then + begin + { don't integrate the offset yet, make_simple_ref() may be able to + handle it more efficiently later (unless an offset is all we have + -> optimization for someone that wants to add support for AArch64 + embedded targets) } + oldoffset:=location.reference.offset; + location.reference.offset:=0; + base:=cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,base); + reference_reset_base(location.reference,base,oldoffset,location.reference.alignment); + end; + shift:=BsfDWord(l); + location.reference.index:=maybe_const_reg; + { sign/zero-extend? } + if regsize.size=8 then + if shift<>0 then + location.reference.shiftmode:=SM_LSL + else + location.reference.shiftmode:=SM_NONE + else if is_signed(regsize) then + location.reference.shiftmode:=SM_SXTW + else if shift<>0 then + location.reference.shiftmode:=SM_UXTW + else + { the upper 32 bits are always already zero-extended -> just use 64 bit + register } + location.reference.index:=cg.makeregsize(current_asmdata.CurrAsmList,location.reference.index,OS_64); + location.reference.shiftimm:=shift; + location.reference.alignment:=newalignment(location.reference.alignment,l); + end; + + +begin + cloadparentfpnode:=taarch64loadparentfpnode; + cvecnode:=taarch64vecnode; +end. diff --git a/fpcsrc/compiler/aarch64/ncpuset.pas b/fpcsrc/compiler/aarch64/ncpuset.pas new file mode 100644 index 00000000..a253afb9 --- /dev/null +++ b/fpcsrc/compiler/aarch64/ncpuset.pas @@ -0,0 +1,175 @@ +{ + Copyright (c) 2015 by Jonas Maebe + + Generate AArch64 assembler for in set/case nodes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit ncpuset; + +{$i fpcdefs.inc} + +interface + + uses + node,nset,ncgset,cpubase,cgbase,cgobj,aasmbase,aasmtai,aasmdata,globtype; + + type + taarch64casenode = 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,regvars,rgobj,aasmcpu, + procinfo, + cgutils; + +{***************************************************************************** + TCGCASENODE +*****************************************************************************} + + + procedure taarch64casenode.optimizevalues(var max_linear_list: aint; var max_dist: aword); + begin + max_linear_list:=10; + end; + + + function taarch64casenode.has_jumptable: boolean; + begin + has_jumptable:=true; + end; + + + procedure taarch64casenode.genjumptable(hp: pcaselabel; min_, max_: aint); + var + last: TConstExprInt; + tablelabel: TAsmLabel; + basereg,indexreg,jumpreg: TRegister; + href: TReference; + opcgsize: tcgsize; + sectype: TAsmSectiontype; + jtitemconsttype: taiconst_type; + + procedure genitem(list:TAsmList;t : pcaselabel); + var + i : aint; + begin + if assigned(t^.less) then + genitem(list,t^.less); + { fill possible hole } + i:=last.svalue+1; + while i<=t^._low.svalue-1 do + begin + list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,elselabel)); + inc(i); + end; + i:=t^._low.svalue; + while i<=t^._high.svalue do + begin + list.concat(Tai_const.Create_rel_sym(jtitemconsttype,tablelabel,blocklabel(t^.blockid))); + inc(i); + end; + last:=t^._high; + if assigned(t^.greater) then + genitem(list,t^.greater); + end; + + begin + if not(target_info.system in systems_darwin) then + jtitemconsttype:=aitconst_32bit + else + { see https://gmplib.org/list-archives/gmp-bugs/2012-December/002836.html } + jtitemconsttype:=aitconst_darwin_dwarf_delta32; + + last:=min_; + opcgsize:=def_cgsize(opsize); + { a <= x <= b <-> unsigned(x-a) <= (b-a) } + cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SUB,opcgsize,aint(min_),hregister); + if not(jumptable_no_range) then + begin + { case expr greater than max_ => goto elselabel } + cg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,opcgsize,OC_A,aint(max_)-aint(min_),hregister,elselabel); + min_:=0; + end; + { local label in order to avoid using GOT } + current_asmdata.getlabel(tablelabel,alt_data); + indexreg:=cg.makeregsize(current_asmdata.CurrAsmList,hregister,OS_ADDR); + cg.a_load_reg_reg(current_asmdata.CurrAsmList,opcgsize,OS_ADDR,hregister,indexreg); + { load table address } + reference_reset_symbol(href,tablelabel,0,4); + basereg:=cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,basereg); + { load table slot, 32-bit sign extended } + reference_reset_base(href,basereg,0,4); + href.index:=indexreg; + href.shiftmode:=SM_LSL; + href.shiftimm:=2; + jumpreg:=cg.getaddressregister(current_asmdata.CurrAsmList); + cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_S32,OS_ADDR,href,jumpreg); + { add table address } + cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,basereg,jumpreg); + { and finally jump } + current_asmdata.CurrAsmList.concat(taicpu.op_reg(A_BR,jumpreg)); + { generate jump table } + if not(target_info.system in systems_darwin) then + sectype:=sec_rodata + else + begin + { on Mac OS X, dead code stripping ("smart linking") happens based on + global symbols: every global/static symbol (symbols that do not + start with "L") marks the start of a new "subsection" that is + discarded by the linker if there are no references to this symbol. + This means that if you put the jump table in the rodata section, it + will become part of the block of data associated with the previous + non-L-label in the rodata section and stay or be thrown away + depending on whether that block of data is referenced. Therefore, + jump tables must be added in the code section and since aktlocaldata + is inserted right after the routine, it will become part of the + same subsection that contains the routine's code } + sectype:=sec_code; + end; + new_section(current_procinfo.aktlocaldata,sectype,current_procinfo.procdef.mangledname,4); + if target_info.system in systems_darwin then + begin + { additionally, these tables are now marked via ".data_region jt32" + and ".end_data_region" } + current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_data_region,'jt32')); + end; + current_procinfo.aktlocaldata.concat(Tai_label.Create(tablelabel)); + genitem(current_procinfo.aktlocaldata,hp); + if target_info.system in systems_darwin then + current_procinfo.aktlocaldata.concat(tai_directive.Create(asd_end_data_region,'')); + end; + + +begin + ccasenode:=taarch64casenode; +end. diff --git a/fpcsrc/compiler/aarch64/ra64con.inc b/fpcsrc/compiler/aarch64/ra64con.inc index 141d7a1c..0092d15a 100644 --- a/fpcsrc/compiler/aarch64/ra64con.inc +++ b/fpcsrc/compiler/aarch64/ra64con.inc @@ -64,6 +64,8 @@ NR_W30 = tregister($0104001E); NR_X30 = tregister($0105001E); NR_WZR = tregister($0104001F); NR_XZR = tregister($0105001F); +NR_WSP = tregister($01040020); +NR_SP = tregister($01050020); NR_B0 = tregister($04010000); NR_H0 = tregister($04030000); NR_S0 = tregister($04090000); @@ -225,3 +227,6 @@ NR_S31 = tregister($0409001F); NR_D31 = tregister($040a001F); NR_Q31 = tregister($0405001F); NR_NZCV = tregister($05000000); +NR_FPCR = tregister($05000001); +NR_FPSR = tregister($05000002); +NR_TPIDR_EL0 = tregister($05000003); diff --git a/fpcsrc/compiler/aarch64/ra64dwa.inc b/fpcsrc/compiler/aarch64/ra64dwa.inc index 1198db78..eaaf04fa 100644 --- a/fpcsrc/compiler/aarch64/ra64dwa.inc +++ b/fpcsrc/compiler/aarch64/ra64dwa.inc @@ -64,164 +64,169 @@ 30, 31, 31, +31, +31, +64, +64, +64, +64, +64, +65, +65, +65, +65, +65, +66, +66, +66, +66, +66, +67, +67, +67, +67, +67, +68, +68, +68, +68, +68, +69, +69, +69, +69, +69, +70, +70, +70, +70, +70, +71, +71, +71, +71, +71, +72, +72, +72, +72, +72, +73, +73, +73, +73, +73, +74, +74, +74, +74, +74, +75, +75, +75, +75, +75, +76, +76, +76, +76, +76, +77, +77, +77, +77, +77, +78, +78, +78, +78, +78, +79, +79, +79, +79, +79, +80, +80, +80, +80, +80, +81, +81, +81, +81, +81, +82, +82, +82, +82, +82, +83, +83, +83, +83, +83, +84, +84, +84, +84, +84, +85, +85, +85, +85, +85, +86, +86, +86, +86, +86, +87, +87, +87, +87, +87, +88, +88, +88, +88, +88, +89, +89, +89, +89, +89, +90, +90, +90, +90, +90, +91, +91, +91, +91, +91, +92, +92, +92, +92, +92, +93, +93, +93, +93, +93, +94, +94, +94, +94, +94, +95, +95, +95, +95, +95, 0, 0, 0, -0, -0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -7, -7, -7, -7, -7, -8, -8, -8, -8, -8, -9, -9, -9, -9, -9, -10, -10, -10, -10, -10, -11, -11, -11, -11, -11, -12, -12, -12, -12, -12, -13, -13, -13, -13, -13, -14, -14, -14, -14, -14, -15, -15, -15, -15, -15, -16, -16, -16, -16, -16, -17, -17, -17, -17, -17, -18, -18, -18, -18, -18, -19, -19, -19, -19, -19, -20, -20, -20, -20, -20, -21, -21, -21, -21, -21, -22, -22, -22, -22, -22, -23, -23, -23, -23, -23, -24, -24, -24, -24, -24, -25, -25, -25, -25, -25, -26, -26, -26, -26, -26, -27, -27, -27, -27, -27, -28, -28, -28, -28, -28, -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, 0 diff --git a/fpcsrc/compiler/aarch64/ra64nor.inc b/fpcsrc/compiler/aarch64/ra64nor.inc index cce0278c..a7bff1f7 100644 --- a/fpcsrc/compiler/aarch64/ra64nor.inc +++ b/fpcsrc/compiler/aarch64/ra64nor.inc @@ -1,2 +1,2 @@ { don't edit, this file is generated from a64reg.dat } -226 +231 diff --git a/fpcsrc/compiler/aarch64/ra64num.inc b/fpcsrc/compiler/aarch64/ra64num.inc index 6cdb6b8b..4173686c 100644 --- a/fpcsrc/compiler/aarch64/ra64num.inc +++ b/fpcsrc/compiler/aarch64/ra64num.inc @@ -64,6 +64,8 @@ tregister($0104001E), tregister($0105001E), tregister($0104001F), tregister($0105001F), +tregister($01040020), +tregister($01050020), tregister($04010000), tregister($04030000), tregister($04090000), @@ -224,4 +226,7 @@ tregister($0403001F), tregister($0409001F), tregister($040a001F), tregister($0405001F), -tregister($05000000) +tregister($05000000), +tregister($05000001), +tregister($05000002), +tregister($05000003) diff --git a/fpcsrc/compiler/aarch64/ra64rni.inc b/fpcsrc/compiler/aarch64/ra64rni.inc index 29b24dae..d818e4d5 100644 --- a/fpcsrc/compiler/aarch64/ra64rni.inc +++ b/fpcsrc/compiler/aarch64/ra64rni.inc @@ -32,6 +32,7 @@ 59, 61, 63, +65, 2, 4, 6, @@ -64,102 +65,7 @@ 60, 62, 64, -65, -70, -75, -80, -85, -90, -95, -100, -105, -110, -115, -120, -125, -130, -135, -140, -145, -150, -155, -160, -165, -170, -175, -180, -185, -190, -195, -200, -205, -210, -215, -220, 66, -71, -76, -81, -86, -91, -96, -101, -106, -111, -116, -121, -126, -131, -136, -141, -146, -151, -156, -161, -166, -171, -176, -181, -186, -191, -196, -201, -206, -211, -216, -221, -69, -74, -79, -84, -89, -94, -99, -104, -109, -114, -119, -124, -129, -134, -139, -144, -149, -154, -159, -164, -169, -174, -179, -184, -189, -194, -199, -204, -209, -214, -219, -224, 67, 72, 77, @@ -224,4 +130,103 @@ 213, 218, 223, -225 +71, +76, +81, +86, +91, +96, +101, +106, +111, +116, +121, +126, +131, +136, +141, +146, +151, +156, +161, +166, +171, +176, +181, +186, +191, +196, +201, +206, +211, +216, +221, +226, +69, +74, +79, +84, +89, +94, +99, +104, +109, +114, +119, +124, +129, +134, +139, +144, +149, +154, +159, +164, +169, +174, +179, +184, +189, +194, +199, +204, +209, +214, +219, +224, +70, +75, +80, +85, +90, +95, +100, +105, +110, +115, +120, +125, +130, +135, +140, +145, +150, +155, +160, +165, +170, +175, +180, +185, +190, +195, +200, +205, +210, +215, +220, +225, +227, +228, +229, +230 diff --git a/fpcsrc/compiler/aarch64/ra64sri.inc b/fpcsrc/compiler/aarch64/ra64sri.inc index a3e6620e..570563bb 100644 --- a/fpcsrc/compiler/aarch64/ra64sri.inc +++ b/fpcsrc/compiler/aarch64/ra64sri.inc @@ -1,8 +1,39 @@ { don't edit, this file is generated from a64reg.dat } 0, -65, +67, +72, +117, +122, +127, +132, +137, +142, +147, +152, +157, +162, +77, +167, +172, +177, +182, +187, +192, +197, +202, +207, +212, +82, +217, +222, +87, +92, +97, +102, +107, +112, 70, -115, +75, 120, 125, 130, @@ -12,8 +43,8 @@ 150, 155, 160, -75, 165, +80, 170, 175, 180, @@ -23,15 +54,18 @@ 200, 205, 210, -80, 215, -220, 85, +220, +225, 90, 95, 100, 105, 110, +115, +228, +229, 68, 73, 118, @@ -64,9 +98,9 @@ 103, 108, 113, -66, +227, 71, -116, +76, 121, 126, 131, @@ -76,8 +110,8 @@ 151, 156, 161, -76, 166, +81, 171, 176, 181, @@ -87,16 +121,16 @@ 201, 206, 211, -81, 216, -221, 86, +221, +226, 91, 96, 101, 106, 111, -225, +116, 69, 74, 119, @@ -129,38 +163,8 @@ 104, 109, 114, -67, -72, -117, -122, -127, -132, -137, -142, -147, -152, -157, -162, -77, -167, -172, -177, -182, -187, -192, -197, -202, -207, -212, -82, -217, -222, -87, -92, -97, -102, -107, -112, +66, +230, 1, 3, 21, @@ -192,6 +196,7 @@ 15, 17, 19, +65, 63, 2, 4, diff --git a/fpcsrc/compiler/aarch64/ra64sta.inc b/fpcsrc/compiler/aarch64/ra64sta.inc index 1198db78..eaaf04fa 100644 --- a/fpcsrc/compiler/aarch64/ra64sta.inc +++ b/fpcsrc/compiler/aarch64/ra64sta.inc @@ -64,164 +64,169 @@ 30, 31, 31, +31, +31, +64, +64, +64, +64, +64, +65, +65, +65, +65, +65, +66, +66, +66, +66, +66, +67, +67, +67, +67, +67, +68, +68, +68, +68, +68, +69, +69, +69, +69, +69, +70, +70, +70, +70, +70, +71, +71, +71, +71, +71, +72, +72, +72, +72, +72, +73, +73, +73, +73, +73, +74, +74, +74, +74, +74, +75, +75, +75, +75, +75, +76, +76, +76, +76, +76, +77, +77, +77, +77, +77, +78, +78, +78, +78, +78, +79, +79, +79, +79, +79, +80, +80, +80, +80, +80, +81, +81, +81, +81, +81, +82, +82, +82, +82, +82, +83, +83, +83, +83, +83, +84, +84, +84, +84, +84, +85, +85, +85, +85, +85, +86, +86, +86, +86, +86, +87, +87, +87, +87, +87, +88, +88, +88, +88, +88, +89, +89, +89, +89, +89, +90, +90, +90, +90, +90, +91, +91, +91, +91, +91, +92, +92, +92, +92, +92, +93, +93, +93, +93, +93, +94, +94, +94, +94, +94, +95, +95, +95, +95, +95, 0, 0, 0, -0, -0, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -3, -3, -3, -3, -3, -4, -4, -4, -4, -4, -5, -5, -5, -5, -5, -6, -6, -6, -6, -6, -7, -7, -7, -7, -7, -8, -8, -8, -8, -8, -9, -9, -9, -9, -9, -10, -10, -10, -10, -10, -11, -11, -11, -11, -11, -12, -12, -12, -12, -12, -13, -13, -13, -13, -13, -14, -14, -14, -14, -14, -15, -15, -15, -15, -15, -16, -16, -16, -16, -16, -17, -17, -17, -17, -17, -18, -18, -18, -18, -18, -19, -19, -19, -19, -19, -20, -20, -20, -20, -20, -21, -21, -21, -21, -21, -22, -22, -22, -22, -22, -23, -23, -23, -23, -23, -24, -24, -24, -24, -24, -25, -25, -25, -25, -25, -26, -26, -26, -26, -26, -27, -27, -27, -27, -27, -28, -28, -28, -28, -28, -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, 0 diff --git a/fpcsrc/compiler/aarch64/ra64std.inc b/fpcsrc/compiler/aarch64/ra64std.inc index 039d5fff..1eaedf8a 100644 --- a/fpcsrc/compiler/aarch64/ra64std.inc +++ b/fpcsrc/compiler/aarch64/ra64std.inc @@ -64,6 +64,8 @@ 'x30', 'wzr', 'xzr', +'wsp', +'sp', 'b0', 'h0', 's0', @@ -224,4 +226,7 @@ 's31', 'd31', 'q31', -'nzcv' +'nzcv', +'fpcr', +'fpsr', +'tpidr_el0' diff --git a/fpcsrc/compiler/aarch64/ra64sup.inc b/fpcsrc/compiler/aarch64/ra64sup.inc index 730f708a..0e59c014 100644 --- a/fpcsrc/compiler/aarch64/ra64sup.inc +++ b/fpcsrc/compiler/aarch64/ra64sup.inc @@ -64,6 +64,8 @@ RS_W30 = $1E; RS_X30 = $1E; RS_WZR = $1F; RS_XZR = $1F; +RS_WSP = $20; +RS_SP = $20; RS_B0 = $00; RS_H0 = $00; RS_S0 = $00; @@ -225,3 +227,6 @@ RS_S31 = $1F; RS_D31 = $1F; RS_Q31 = $1F; RS_NZCV = $00; +RS_FPCR = $01; +RS_FPSR = $02; +RS_TPIDR_EL0 = $03; diff --git a/fpcsrc/compiler/aarch64/racpu.pas b/fpcsrc/compiler/aarch64/racpu.pas new file mode 100644 index 00000000..b043e147 --- /dev/null +++ b/fpcsrc/compiler/aarch64/racpu.pas @@ -0,0 +1,88 @@ +{ + Copyright (c) 1998-2003 by Carl Eric Codere and Peter Vreman + Copyright (c) 2014 by Jonas Maebe + + Handles the common AArch64 assembler reader routines + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +unit racpu; + +{$i fpcdefs.inc} + + interface + + uses + cgbase, + cpubase, + aasmtai,aasmdata, + rautils; + + type + TAArch64Operand=class(TOperand) + end; + + TAArch64Instruction=class(TInstruction) + oppostfix : toppostfix; + function ConcatInstruction(p:TAsmList) : tai;override; + function Is64bit: boolean; + function cgsize: tcgsize; + end; + + implementation + + uses + verbose, + aasmcpu; + + function TAArch64Instruction.ConcatInstruction(p:TAsmList) : tai; + begin + result:=inherited ConcatInstruction(p); + taicpu(result).oppostfix:=oppostfix; + end; + + + function TAArch64Instruction.Is64bit: boolean; + begin + result:= + (operands[1].opr.typ=OPR_REGISTER) and + (getsubreg(operands[1].opr.reg)=R_SUBQ); + end; + + function TAArch64Instruction.cgsize: tcgsize; + begin + if ops<1 then + internalerror(2014122001); + if operands[1].opr.typ<>OPR_REGISTER then + internalerror(2014122002); + result:=reg_cgsize(operands[1].opr.reg); + { a 32 bit integer register could actually be 16 or 8 bit } + if result=OS_32 then + case oppostfix of + PF_B: + result:=OS_8; + PF_SB: + result:=OS_S8; + PF_H: + result:=OS_16; + PF_SH: + result:=OS_S16; + end; + end; + + +end. diff --git a/fpcsrc/compiler/aarch64/racpugas.pas b/fpcsrc/compiler/aarch64/racpugas.pas new file mode 100644 index 00000000..b0d6b886 --- /dev/null +++ b/fpcsrc/compiler/aarch64/racpugas.pas @@ -0,0 +1,1053 @@ +{ + Copyright (c) 1998-2002 by Carl Eric Codere and Peter Vreman + Copyright (c) 2014 by Jonas Maebe + + Does the parsing for the AArch64 GNU AS styled inline assembler. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + **************************************************************************** +} +Unit racpugas; + +{$i fpcdefs.inc} + + Interface + + uses + raatt,racpu, + cpubase; + + type + taarch64attreader = class(tattreader) + actoppostfix : TOpPostfix; + function is_asmopcode(const s: string):boolean;override; + function is_register(const s:string):boolean;override; + procedure handleopcode;override; + procedure BuildReference(oper: taarch64operand; is64bit: boolean); + procedure BuildOperand(oper: taarch64operand; is64bit: boolean); + function TryBuildShifterOp(instr: taarch64instruction; opnr: longint) : boolean; + procedure BuildOpCode(instr: taarch64instruction); + procedure ReadSym(oper: taarch64operand; is64bit: boolean); + procedure ConvertCalljmp(instr: taarch64instruction); + function ToConditionCode(const hs: string; is_operand: boolean): tasmcond; + end; + + + Implementation + + uses + { helpers } + cutils, + { global } + globtype,verbose, + systems,aasmbase,aasmtai,aasmdata,aasmcpu, + { symtable } + symconst,symsym, + procinfo, + rabase,rautils, + cgbase,cgutils; + + + function taarch64attreader.is_register(const s:string):boolean; + type + treg2str = record + name : string[3]; + reg : tregister; + end; + + const + extraregs : array[0..3] of treg2str = ( + (name: 'FP' ; reg: NR_FP), + (name: 'LR' ; reg: NR_LR), + (name: 'IP0'; reg: NR_IP0), + (name: 'IP1'; reg: NR_IP1)); + + var + i : longint; + + begin + result:=inherited is_register(s); + { reg found? + possible aliases are always 2 or 3 chars + } + 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; + + + procedure taarch64attreader.ReadSym(oper: taarch64operand; is64bit: boolean); + 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,is64bit); + 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 taarch64attreader.BuildReference(oper: taarch64operand; is64bit: boolean); + + procedure do_error; + begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + end; + + + procedure test_end(require_rbracket : boolean); + begin + if require_rbracket then begin + if not(actasmtoken=AS_RBRACKET) then + begin + do_error; + exit; + end + else + Consume(AS_RBRACKET); + if (actasmtoken=AS_NOT) then + begin + oper.opr.ref.addressmode:=AM_PREINDEXED; + Consume(AS_NOT); + end; + end; + if not(actasmtoken in [AS_SEPARATOR,AS_end]) then + do_error + else + begin +{$IFDEF debugasmreader} + writeln('TEST_end_FINAL_OK. Created the following ref:'); + writeln('oper.opr.ref.shiftimm=',oper.opr.ref.shiftimm); + writeln('oper.opr.ref.shiftmode=',ord(oper.opr.ref.shiftmode)); + writeln('oper.opr.ref.index=',ord(oper.opr.ref.index)); + writeln('oper.opr.ref.base=',ord(oper.opr.ref.base)); + writeln('oper.opr.ref.signindex=',ord(oper.opr.ref.signindex)); + writeln('oper.opr.ref.addressmode=',ord(oper.opr.ref.addressmode)); + writeln; +{$endIF debugasmreader} + end; + end; + + + function is_shifter_ref_operation(var a : tshiftmode) : boolean; + begin + a:=SM_NONE; + if (actasmpattern='LSL') then + a:=SM_LSL + else if (actasmpattern='UXTW') then + a:=SM_UXTW + else if (actasmpattern='SXTW') then + a:=SM_SXTW + else if (actasmpattern='SXTX') then + a:=SM_SXTX; + is_shifter_ref_operation:=not(a=SM_NONE); + end; + + + procedure read_index_shift(require_rbracket : boolean); + var + shift: aint; + begin + case actasmtoken of + AS_COMMA : + begin + Consume(AS_COMMA); + if not(actasmtoken=AS_ID) then + do_error; + if is_shifter_ref_operation(oper.opr.ref.shiftmode) then + begin + Consume(actasmtoken); + if actasmtoken=AS_HASH then + begin + Consume(AS_HASH); + shift:=BuildConstExpression(false,true); + if not(shift in [0,2+ord(is64bit)]) then + do_error; + oper.opr.ref.shiftimm:=shift; + test_end(require_rbracket); + end; + end + else + begin + do_error; + exit; + end; + end; + AS_RBRACKET : + if require_rbracket then + test_end(require_rbracket) + else + begin + do_error; + exit; + end; + AS_SEPARATOR,AS_END : + if not require_rbracket then + test_end(false) + else + do_error; + else + begin + do_error; + exit; + end; + end; + end; + + + procedure read_index(require_rbracket : boolean); + var + recname : string; + o_int,s_int : aint; + begin + case actasmtoken of + AS_REGISTER : + begin + if getsupreg(actasmregister)=RS_XZR then + Message1(asmr_e_invalid_ref_register,actasmpattern); + oper.opr.ref.index:=actasmregister; + Consume(AS_REGISTER); + read_index_shift(require_rbracket); + exit; + end; + AS_HASH : // constant + begin + Consume(AS_HASH); +(* + if actasmtoken=AS_COLON then + begin + consume(AS_COLON); + { GNU-style lower 12 bits of address of non-GOT-based + access } + if (actasmpattern='LO12') then + begin + consume(actasmtoken); + consume(AS_COLON); + if not oper.SetupVar(actasmpattern,false) then + begin + do_error; + exit + end; + consume(AS_ID); + oper.opr.ref.refaddr:=addr_??? (not gotpageoffset); + end + else + begin + do_error; + exit + end; + end + else +*) + begin + o_int:=BuildConstExpression(false,true); + inc(oper.opr.ref.offset,o_int); + end; + test_end(require_rbracket); + exit; + end; + AS_ID : + begin + recname:=actasmpattern; + Consume(AS_ID); + { Apple-style got page offset } + if actasmtoken=AS_AT then + begin + if not oper.SetupVar(recname,false) then + begin + do_error; + exit + end; + consume(AS_AT); + if actasmpattern='GOTPAGEOFF' then + begin + consume(actasmtoken); + oper.opr.ref.refaddr:=addr_gotpageoffset; + end + else if actasmpattern='PAGEOFF' then + begin + consume(actasmtoken); + oper.opr.ref.refaddr:=addr_pageoffset; + end + else + begin + do_error; + exit + end; + end + else + begin + BuildRecordOffsetSize(recname,o_int,s_int,recname,false); + inc(oper.opr.ref.offset,o_int); + end; + test_end(require_rbracket); + exit; + end; + AS_AT: + begin + do_error; + exit; + end; + AS_RBRACKET : + begin + if require_rbracket then + begin + test_end(require_rbracket); + exit; + end + else + begin + do_error; // unexpected rbracket + exit; + end; + end; + AS_SEPARATOR,AS_end : + begin + if not require_rbracket then + begin + test_end(false); + exit; + end + else + begin + do_error; + exit; + end; + end; + else + begin + // unexpected token + do_error; + exit; + end; + end; // case + end; + + + procedure try_prepostindexed; + begin + Consume(AS_RBRACKET); + case actasmtoken of + AS_COMMA : + begin // post-indexed + Consume(AS_COMMA); + oper.opr.ref.addressmode:=AM_POSTINDEXED; + read_index(false); + exit; + end; + AS_NOT : + begin // pre-indexed + Consume(AS_NOT); + oper.opr.ref.addressmode:=AM_PREINDEXED; + test_end(false); + exit; + end; + else + begin + test_end(false); + exit; + end; + end; // case + end; + + begin + Consume(AS_LBRACKET); + oper.opr.ref.addressmode:=AM_OFFSET; // assume "neither PRE nor POST inc" + if actasmtoken=AS_REGISTER then + begin + if getsupreg(actasmregister)=RS_XZR then + Message1(asmr_e_invalid_ref_register,actasmpattern); + oper.opr.ref.base:=actasmregister; + Consume(AS_REGISTER); + case actasmtoken of + AS_RBRACKET : + begin + try_prepostindexed; + exit; + end; + AS_COMMA : + begin + Consume(AS_COMMA); + read_index(true); + exit; + end; + else + begin + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + end; + end; + end + else + Begin + case actasmtoken of + AS_ID : + begin + { TODO: local variables and parameters } + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + exit; + end; + else + begin // elsecase + Message(asmr_e_invalid_reference_syntax); + RecoverConsume(false); + exit; + end; + end; + end; + end; + + + function taarch64attreader.TryBuildShifterOp(instr: taarch64instruction; opnr: longint): boolean; + + procedure handlepara(sm : tshiftmode); + begin + consume(AS_ID); + fillchar(instr.operands[opnr].opr,sizeof(instr.operands[opnr].opr),0); + instr.operands[opnr].opr.typ:=OPR_SHIFTEROP; + instr.operands[opnr].opr.shifterop.shiftmode:=sm; + if (sm=SM_LSL) or + (actasmtoken=AS_HASH) then + begin + consume(AS_HASH); + instr.operands[opnr].opr.shifterop.shiftimm:=BuildConstExpression(false,false); + end; + end; + + const + shiftmode2str: array[SM_LSL..SM_SXTX] of string[4] = + ('LSL','LSR','ASR', + 'UXTB','UXTH','UXTW','UXTX', + 'SXTB','SXTH','SXTW','SXTX'); + var + sm: tshiftmode; + i: longint; + usessp, + useszr: boolean; + begin + result:=false; + if (actasmtoken=AS_ID) then + begin + for sm:=low(shiftmode2str) to high(shiftmode2str) do + if actasmpattern=shiftmode2str[sm] then + begin + handlepara(sm); + if instr.operands[1].opr.typ=OPR_REGISTER then + begin + { the possible shifter ops depend on whether this + instruction uses sp and/or zr } + usessp:=false; + useszr:=false; + for i:=low(instr.operands) to pred(opnr) do + begin + if (instr.operands[1].opr.typ=OPR_REGISTER) then + case getsupreg(instr.operands[1].opr.reg) of + RS_XZR: + useszr:=true; + RS_SP: + usessp:=true; + end; + end; + result:=valid_shifter_operand(instr.opcode,useszr,usessp,instr.Is64bit,sm,instr.operands[opnr].opr.shifterop.shiftimm); + end + end; + end; + end; + + + function taarch64attreader.ToConditionCode(const hs: string; is_operand: boolean): tasmcond; + begin + case actopcode of + A_CSEL,A_CSINC,A_CSINV,A_CSNEG,A_CSET,A_CSETM, + A_CINC,A_CINV,A_CNEG,A_CCMN,A_CCMP, + A_B: + begin + { search for condition, conditions are always 2 chars } + if (is_operand<>(actopcode=A_B)) and + (length(hs)>1) then + begin + { workaround for DFA bug } + result:=low(tasmcond); + for result:=low(tasmcond) to high(tasmcond) do + begin + if hs=uppercond2str[result] then + exit; + end; + end; + end; + end; + result:=C_None;; + end; + + + Procedure taarch64attreader.BuildOperand(oper: taarch64operand; is64bit: boolean); + var + expr: string; + typesize, l: aint; + + procedure MaybeAddGotAddrMode; + begin + if actasmtoken=AS_AT then + begin + consume(AS_AT); + if actasmpattern='GOTPAGE' then + oper.opr.ref.refaddr:=addr_gotpage + else if actasmpattern='GOTPAGEOFF' then + oper.opr.ref.refaddr:=addr_gotpageoffset + else if actasmpattern='PAGE' then + oper.opr.ref.refaddr:=addr_page + else if actasmpattern='PAGEOFF' then + oper.opr.ref.refaddr:=addr_pageoffset + else + Message(asmr_e_expr_illegal); + consume(actasmtoken); + end + else + oper.opr.ref.refaddr:=addr_pic; + end; + + 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 if (actopcode=A_ADR) or + (actopcode=A_ADRP) then + begin + oper.InitRef; + MaybeAddGotAddrMode; + oper.opr.ref.symbol:=hl; + if (actasmtoken in [AS_PLUS, AS_MINUS]) then + begin + l:=BuildConstExpression(true,false); + oper.opr.ref.offset:=l; + end; + 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 + (tabstractnormalvarsym(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 : + inc(oper.opr.val,l); + OPR_REFERENCE : + 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.RefAsmSymbol(mangledname); + end + else + inc(oper.opr.val,l); + OPR_SYMBOL: + Message(asmr_e_invalid_symbol_ref); + else + internalerror(200309221); + end; + end; + + + function MaybeBuildReference(is64bit: boolean):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,is64bit); + end; + AS_LPAREN: + BuildReference(oper,is64bit); + AS_ID: { only a variable is allowed ... } + Begin + ReadSym(oper,is64bit); + case actasmtoken of + AS_end, + AS_SEPARATOR, + AS_COMMA: ; + AS_LPAREN: + BuildReference(oper,is64bit); + 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; + icond: tasmcond; + Begin + expr:=''; + case actasmtoken of + AS_LBRACKET: { Memory reference or constant expression } + Begin + oper.InitRef; + BuildReference(oper,is64bit); + end; + + AS_HASH: { Constant expression } + Begin + Consume(AS_HASH); + BuildConstantOperand(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,is64bit); + end; + *) + AS_ID: { A constant expression, or a Variable ref. } + Begin + { Condition code? } + icond:=ToConditionCode(actasmpattern,true); + if icond<>C_None then + begin + oper.opr.typ:=OPR_COND; + oper.opr.cc:=icond; + 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,is64bit); + Consume(AS_RPAREN); + if oper.opr.typ in [OPR_REFERENCE,OPR_LOCAL] then + oper.SetSize(typesize,true); + end + else + begin + if not(oper.SetupVar(expr,false)) then + 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 + else + MaybeAddGotAddrMode; + 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,is64bit); + end; + + { Register, a variable reference or a constant reference } + AS_REGISTER: + Begin + { save the type of register used. } + tempreg:=actasmregister; + Consume(AS_REGISTER); + if (actasmtoken in [AS_end,AS_SEPARATOR,AS_COMMA]) then + Begin + 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 } + end; + +{***************************************************************************** + taarch64attreader +*****************************************************************************} + + procedure taarch64attreader.BuildOpCode(instr: taarch64instruction); + 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; + oppostfix:=actoppostfix; + end; + Consume(AS_OPCODE); + + { We are reading operands, so opcode will be an AS_ID } + operandnum:=1; + { Zero operand opcode ? } + if actasmtoken in [AS_SEPARATOR,AS_end] then + begin + instr.Ops:=0; + exit; + end; + { Read the operands } + repeat + case actasmtoken of + AS_COMMA: { Operand delimiter } + Begin + { operandnum and not operandnum+1, because tinstruction is + one-based and taicpu is zero-based) + } + if can_be_shifter_operand(instr.opcode,operandnum) then + begin + Consume(AS_COMMA); + if not TryBuildShifterOp(instr,operandnum+1) then + Message(asmr_e_illegal_shifterop_syntax); + Inc(operandnum); + end + else + begin + if operandnum>Max_Operands then + Message(asmr_e_too_many_operands) + else + Inc(operandnum); + Consume(AS_COMMA); + end; + end; + AS_SEPARATOR, + AS_end : { End of asm operands for this opcode } + begin + break; + end; + else + begin + BuildOperand(taarch64operand(instr.operands[operandnum]),instr.Is64bit); + instr.Ops:=operandnum; + if instr.operands[operandnum].opr.typ=OPR_REFERENCE then + if simple_ref_type(instr.opcode,instr.cgsize,instr.oppostfix,instr.operands[operandnum].opr.ref)<>sr_simple then + Message(asmr_e_invalid_reference_syntax); + ; + end; + end; { end case } + until false; + end; + + + function taarch64attreader.is_asmopcode(const s: string):boolean; + + const + { sorted by length so longer postfixes will match first } + postfix2strsorted : array[1..7] of string[3] = ( + 'SB','SH','SW', + 'B','H','W', + 'S'); + + postfixsorted : array[1..7] of TOpPostfix = ( + PF_SB,PF_SH,PF_SW, + PF_B,PF_H,PF_W, + PF_S); + + var + j : longint; + hs : string; + maxlen : longint; + icond : tasmcond; + Begin + { making s a value parameter would break other assembler readers } + hs:=s; + is_asmopcode:=false; + + { clear opcode } + actopcode:=A_None; + actcondition:=C_None; + + { b.cond ? } + if (length(hs)=4) and + (hs[1]='B') and + (hs[2]='.') then + begin + actopcode:=A_B; + actasmtoken:=AS_OPCODE; + actcondition:=ToConditionCode(copy(hs,3,length(actasmpattern)-2),false); + if actcondition<>C_None then + is_asmopcode:=true; + exit; + end; + + maxlen:=max(length(hs),7); + actopcode:=A_NONE; + for j:=maxlen downto 1 do + begin + actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j)))); + if actopcode<>A_NONE then + begin + actasmtoken:=AS_OPCODE; + { strip op code } + delete(hs,1,j); + break; + end; + end; + if actopcode=A_NONE then + exit; + + { check for postfix } + if length(hs)>0 then + begin + for j:=low(postfixsorted) to high(postfixsorted) do + begin + if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then + begin + actoppostfix:=postfixsorted[j]; + { strip postfix } + delete(hs,1,length(postfix2strsorted[j])); + break; + end; + end; + end; + { if we stripped all postfixes, it's a valid opcode } + is_asmopcode:=length(hs)=0; + end; + + + procedure taarch64attreader.ConvertCalljmp(instr: taarch64instruction); + var + newopr : toprrec; + begin + if instr.Operands[1].opr.typ=OPR_REFERENCE then + begin + newopr.typ:=OPR_SYMBOL; + newopr.symbol:=instr.Operands[1].opr.ref.symbol; + newopr.symofs:=instr.Operands[1].opr.ref.offset; + if (instr.Operands[1].opr.ref.base<>NR_NO) or + (instr.Operands[1].opr.ref.index<>NR_NO) or + (instr.Operands[1].opr.ref.refaddr<>addr_pic) then + Message(asmr_e_syn_operand); + instr.Operands[1].opr:=newopr; + end; + end; + + procedure taarch64attreader.handleopcode; + var + instr: taarch64instruction; + begin + instr:=taarch64instruction.Create(taarch64operand); + BuildOpcode(instr); + if is_calljmp(instr.opcode) then + ConvertCalljmp(instr); + { + instr.AddReferenceSizes; + instr.SetInstructionOpsize; + instr.CheckOperandSizes; + } + instr.ConcatInstruction(curlist); + instr.Free; + actoppostfix:=PF_None; + end; + + +{***************************************************************************** + Initialize +*****************************************************************************} + +const + asmmode_arm_att_info : tasmmodeinfo = + ( + id : asmmode_arm_gas; + idtxt : 'GAS'; + casmreader : taarch64attreader; + ); + + asmmode_arm_standard_info : tasmmodeinfo = + ( + id : asmmode_standard; + idtxt : 'STANDARD'; + casmreader : taarch64attreader; + ); + +initialization + RegisterAsmMode(asmmode_arm_att_info); + RegisterAsmMode(asmmode_arm_standard_info); +end. diff --git a/fpcsrc/compiler/aarch64/rgcpu.pas b/fpcsrc/compiler/aarch64/rgcpu.pas new file mode 100644 index 00000000..fb9521cd --- /dev/null +++ b/fpcsrc/compiler/aarch64/rgcpu.pas @@ -0,0 +1,171 @@ +{ + Copyright (c) 1998-2002 by Florian Klaempfl + + This unit implements the SPARC 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,aasmcpu,aasmtai,aasmdata, + cgbase,cgutils, + cpubase, + globtype, + rgobj; + + type + trgcpu=class(trgobj) + procedure do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override; + procedure do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister);override; + protected + procedure do_spill_op(list: tasmlist; op: tasmop; pos: tai; const spilltemp: treference; tempreg: tregister); + end; + + trgintcpu=class(trgcpu) + procedure add_cpu_interferences(p: tai); override; + end; + + +implementation + + uses + verbose,cutils, + cgobj; + + procedure trgcpu.do_spill_read(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister); + begin + do_spill_op(list,A_LDR,pos,spilltemp,tempreg); + end; + + + procedure trgcpu.do_spill_written(list:TAsmList;pos:tai;const spilltemp:treference;tempreg:tregister); + begin + do_spill_op(list,A_STR,pos,spilltemp,tempreg); + end; + + + procedure trgcpu.do_spill_op(list: tasmlist; op: tasmop; pos: tai; const spilltemp: treference; tempreg: tregister); + var + helpins : tai; + tmpref : treference; + helplist : TAsmList; + hreg : tregister; + isload : boolean; + begin + isload:=op=A_LDR; + { offset out of range for regular load/store? } + if simple_ref_type(op,reg_cgsize(tempreg),PF_None,spilltemp)<>sr_simple then + begin + helplist:=TAsmList.create; + + if getregtype(tempreg)=R_INTREGISTER then + hreg:=tempreg + else + hreg:=cg.getaddressregister(helplist); + + cg.a_load_const_reg(helplist,OS_ADDR,spilltemp.offset,hreg); + reference_reset_base(tmpref,spilltemp.base,0,sizeof(pint)); + tmpref.index:=hreg; + if isload then + helpins:=spilling_create_load(tmpref,tempreg) + else + helpins:=spilling_create_store(tempreg,tmpref); + helplist.concat(helpins); + add_cpu_interferences(helpins); + list.insertlistafter(pos,helplist); + helplist.free; + end + else if isload then + inherited do_spill_read(list,pos,spilltemp,tempreg) + else + inherited do_spill_written(list,pos,spilltemp,tempreg) + end; + + + procedure trgintcpu.add_cpu_interferences(p: tai); + var + i, j: longint; + begin + if p.typ=ait_instruction then + begin + { add interferences for instructions that can have SP as a register + operand } + case taicpu(p).opcode of + A_MOV: + { all operands can be SP } + exit; + A_ADD, + A_SUB, + A_CMP, + A_CMN: + { ok as destination or first source in immediate or extended + register form } + if (taicpu(p).oper[taicpu(p).ops-1]^.typ<>top_shifterop) or + valid_shifter_operand(taicpu(p).opcode,false,true, + reg_cgsize(taicpu(p).oper[0]^.reg) in [OS_64,OS_S64], + taicpu(p).oper[taicpu(p).ops-1]^.shifterop^.shiftmode, + taicpu(p).oper[taicpu(p).ops-1]^.shifterop^.shiftimm) then + begin + if taicpu(p).oper[taicpu(p).ops-1]^.typ=top_shifterop then + i:=taicpu(p).ops-2 + else + i:=taicpu(p).ops-1; + if (taicpu(p).oper[i]^.typ=top_reg) then + add_edge(getsupreg(taicpu(p).oper[i]^.reg),RS_SP); + exit; + end; + A_AND, + A_EOR, + A_ORR, + A_TST: + { ok in immediate form } + if taicpu(p).oper[taicpu(p).ops-1]^.typ=top_const then + exit; + end; + { add interferences for other registers } + for i:=0 to taicpu(p).ops-1 do + begin + case taicpu(p).oper[i]^.typ of + top_reg: + if getregtype(taicpu(p).oper[i]^.reg)=R_INTREGISTER then + add_edge(getsupreg(taicpu(p).oper[i]^.reg),RS_SP); + top_ref: + begin + { sp can always be base, never be index } + if taicpu(p).oper[i]^.ref^.index<>NR_NO then + add_edge(getsupreg(taicpu(p).oper[i]^.ref^.index),RS_SP); + { in case of write back, the base register must be + different from the loaded/stored register } + if (taicpu(p).oper[i]^.ref^.addressmode in [AM_PREINDEXED,AM_POSTINDEXED]) and + (taicpu(p).oper[i]^.ref^.base<>NR_NO) then + begin + for j:=pred(i) downto 0 do + if taicpu(p).oper[j]^.typ=TOP_REG then + add_edge(getsupreg(taicpu(p).oper[j]^.reg),getsupreg(taicpu(p).oper[i]^.ref^.base)); + end; + end; + end; + end; + end; + end; + +end. diff --git a/fpcsrc/compiler/aasmtai.pas b/fpcsrc/compiler/aasmtai.pas index c3176dc5..989187df 100644 --- a/fpcsrc/compiler/aasmtai.pas +++ b/fpcsrc/compiler/aasmtai.pas @@ -80,7 +80,6 @@ interface ait_labeled_instruction, {$endif m68k} {$ifdef arm} - ait_thumb_func, ait_thumb_set, {$endif arm} ait_set, @@ -198,7 +197,6 @@ interface 'labeled_instr', {$endif m68k} {$ifdef arm} - 'thumb_func', 'thumb_set', {$endif arm} 'set', @@ -221,11 +219,11 @@ interface {$ifdef arm} { ARM only } ,top_regset - ,top_conditioncode ,top_modeflags ,top_specialreg {$endif arm} {$if defined(arm) or defined(aarch64)} + ,top_conditioncode ,top_shifterop {$endif defined(arm) or defined(aarch64)} {$ifdef m68k} @@ -268,12 +266,12 @@ interface top_local : (localoper:plocaloper); {$ifdef arm} top_regset : (regset:^tcpuregisterset; regtyp: tregistertype; subreg: tsubregister; usermode: boolean); - top_conditioncode : (cc : TAsmCond); top_modeflags : (modeflags : tcpumodeflags); top_specialreg : (specialreg:tregister; specialflags:tspecialregflags); {$endif arm} {$if defined(arm) or defined(aarch64)} top_shifterop : (shifterop : pshifterop); + top_conditioncode : (cc : TAsmCond); {$endif defined(arm) or defined(aarch64)} {$ifdef m68k} top_regset : (dataregset,addrregset:^tcpuregisterset); @@ -310,7 +308,6 @@ interface ait_cutobject,ait_marker,ait_varloc,ait_align,ait_section,ait_comment, ait_const,ait_directive, {$ifdef arm} - ait_thumb_func, ait_thumb_set, {$endif arm} ait_set,ait_weak, @@ -356,7 +353,11 @@ interface { for Jasmin } asd_jclass,asd_jinterface,asd_jsuper,asd_jfield,asd_jlimit,asd_jline, { .ent/.end for MIPS and Alpha } - asd_ent,asd_ent_end + asd_ent,asd_ent_end, + { supported by recent clang-based assemblers for data-in-code } + asd_data_region, asd_end_data_region, + { .thumb_func for ARM } + asd_thumb_func ); TAsmSehDirective=( @@ -385,7 +386,11 @@ interface { for Jasmin } 'class','interface','super','field','limit','line', { .ent/.end for MIPS and Alpha } - 'ent','end' + 'ent','end', + { supported by recent clang-based assemblers for data-in-code } + 'data_region','end_data_region', + { .thumb_func for ARM } + 'thumb_func' ); sehdirectivestr : array[TAsmSehDirective] of string[16]=( '.seh_proc','.seh_endproc', @@ -2552,6 +2557,9 @@ implementation {$ifdef ARM} and not(r.base=NR_R15) {$endif ARM} +{$ifdef aarch64} + and not(r.refaddr in [addr_full,addr_gotpageoffset,addr_gotpage]) +{$endif aarch64} then internalerror(200502052); typ:=top_ref; diff --git a/fpcsrc/compiler/aggas.pas b/fpcsrc/compiler/aggas.pas index b764cda3..db63e13d 100644 --- a/fpcsrc/compiler/aggas.pas +++ b/fpcsrc/compiler/aggas.pas @@ -532,6 +532,8 @@ implementation system_powerpc64_darwin, system_x86_64_darwin, system_arm_darwin, + system_aarch64_darwin, + system_x86_64_iphonesim, system_powerpc_aix, system_powerpc64_aix: begin @@ -567,7 +569,8 @@ implementation AsmWriteln('__TEXT,__picsymbolstub4,symbol_stubs,none,16') else AsmWriteln('__TEXT,__symbol_stub4,symbol_stubs,none,12') - { darwin/x86-64 uses RIP-based GOT addressing, no symbol stubs } + { darwin/(x86-64/AArch64) uses PC-based GOT addressing, no + explicit symbol stubs } else internalerror(2006031101); end; @@ -1352,10 +1355,6 @@ implementation AsmWriteLn(tai_symbol(hp).sym.name + '=' + tostr(tai_symbol(hp).value)); end; {$ifdef arm} - ait_thumb_func: - begin - AsmWriteLn(#9'.thumb_func'); - end; ait_thumb_set: begin AsmWriteLn(#9'.thumb_set '+tai_thumb_set(hp).sym^+', '+tai_thumb_set(hp).value^); diff --git a/fpcsrc/compiler/aoptobj.pas b/fpcsrc/compiler/aoptobj.pas index 619e24e0..c875aa32 100644 --- a/fpcsrc/compiler/aoptobj.pas +++ b/fpcsrc/compiler/aoptobj.pas @@ -361,7 +361,7 @@ Unit AoptObj; function JumpTargetOp(ai: taicpu): poper; inline; begin -{$ifdef MIPS} +{$if defined(MIPS)} { MIPS branches can have 1,2 or 3 operands, target label is the last one. } result:=ai.oper[ai.ops-1]; {$else MIPS} @@ -1179,9 +1179,9 @@ Unit AoptObj; function IsJumpToLabel(hp: taicpu): boolean; begin result:=(hp.opcode=aopt_uncondjmp) and -{$ifdef arm} +{$if defined(arm) or defined(aarch64)} (hp.condition=c_None) and -{$endif arm} +{$endif arm or aarch64} (JumpTargetOp(hp)^.typ = top_ref) and (JumpTargetOp(hp)^.ref^.symbol is TAsmLabel); end; @@ -1260,6 +1260,14 @@ Unit AoptObj; exit; if not GetFinalDestination(taicpu(p1),succ(level)) then exit; +{$if defined(aarch64)} + { can't have conditional branches to + global labels on AArch64, because the + offset may become too big } + if not(taicpu(hp).condition in [C_None,C_AL,C_NV]) and + (tasmlabel(JumpTargetOp(taicpu(p1))^.ref^.symbol).bind<>AB_LOCAL) then + exit; +{$endif aarch64} tasmlabel(JumpTargetOp(hp)^.ref^.symbol).decrefs; JumpTargetOp(hp)^.ref^.symbol:=JumpTargetOp(taicpu(p1))^.ref^.symbol; tasmlabel(JumpTargetOp(hp)^.ref^.symbol).increfs; @@ -1398,9 +1406,15 @@ Unit AoptObj; FindLabel(tasmlabel(JumpTargetOp(taicpu(p))^.ref^.symbol), hp2) then begin if (taicpu(p).opcode=aopt_condjmp) - {$ifdef arm} + {$if defined(arm) or defined(aarch64)} and (taicpu(p).condition<>C_None) - {$endif arm} + {$endif arm or aarch64} + {$if defined(aarch64)} + { can't have conditional branches to + global labels on AArch64, because the + offset may become too big } + and (tasmlabel(JumpTargetOp(taicpu(hp1))^.ref^.symbol).bind=AB_LOCAL) + {$endif aarch64} then begin taicpu(p).condition:=inverse_cond(taicpu(p).condition); diff --git a/fpcsrc/compiler/arm/aasmcpu.pas b/fpcsrc/compiler/arm/aasmcpu.pas index 77ee3dc1..7e5d5566 100644 --- a/fpcsrc/compiler/arm/aasmcpu.pas +++ b/fpcsrc/compiler/arm/aasmcpu.pas @@ -30,7 +30,8 @@ uses aasmbase,aasmtai,aasmdata,aasmsym, ogbase, symtype, - cpubase,cpuinfo,cgbase,cgutils; + cpubase,cpuinfo,cgbase,cgutils, + sysutils; const { "mov reg,reg" source operand number } @@ -54,7 +55,8 @@ uses $00000200; OT_SIZE_MASK = $000003FF; { all the size attributes } - OT_NON_SIZE = longint(not OT_SIZE_MASK); + OT_NON_SIZE = $0FFFF800; + OT_OPT_SIZE = $F0000000; OT_SIGNED = $00000100; { the operand need to be signed -128-127 } @@ -73,6 +75,7 @@ uses OT_IMM80 = $00002010; OT_IMMTINY = $00002100; OT_IMMSHIFTER= $00002200; + OT_IMMEDIATEZERO = $10002200; OT_IMMEDIATE24 = OT_IMM24; OT_SHIFTIMM = OT_SHIFTEROP or OT_IMMSHIFTER; OT_SHIFTIMMEDIATE = OT_SHIFTIMM; @@ -85,9 +88,12 @@ uses OT_REG8 = $00201001; OT_REG16 = $00201002; OT_REG32 = $00201004; + OT_REGLO = $10201004; { lower reg (r0-r7) } + OT_REGSP = $20201004; OT_REG64 = $00201008; OT_VREG = $00201010; { vector register } OT_REGF = $00201020; { coproc register } + OT_REGS = $00201040; { special register with mask } OT_MEMORY = $00204000; { register number in 'basereg' } OT_MEM8 = $00204001; OT_MEM16 = $00204002; @@ -96,20 +102,24 @@ uses OT_MEM80 = $00204010; { word/byte load/store } OT_AM2 = $00010000; - { misc ld/st operations } + { misc ld/st operations, thumb reg indexed } OT_AM3 = $00020000; - { multiple ld/st operations } + { multiple ld/st operations or thumb imm indexed } OT_AM4 = $00040000; - { co proc. ld/st operations } + { co proc. ld/st operations or thumb sp+imm indexed } OT_AM5 = $00080000; - OT_AMMASK = $000f0000; + { exclusive ld/st operations or thumb pc+imm indexed } + OT_AM6 = $00100000; + OT_AMMASK = $001f0000; { IT instruction } - OT_CONDITION = $00100000; + OT_CONDITION = $00200000; + OT_MODEFLAGS = $00400000; OT_MEMORYAM2 = OT_MEMORY or OT_AM2; OT_MEMORYAM3 = OT_MEMORY or OT_AM3; OT_MEMORYAM4 = OT_MEMORY or OT_AM4; OT_MEMORYAM5 = OT_MEMORY or OT_AM5; + OT_MEMORYAM6 = OT_MEMORY or OT_AM6; OT_FPUREG = $01000000; { floating point stack registers } OT_REG_SMASK = $00070000; { special register operands: these may be treated differently } @@ -128,9 +138,34 @@ uses IF_NONE = $00000000; IF_ARMMASK = $000F0000; - IF_ARM7 = $00070000; - IF_FPMASK = $00F00000; - IF_FPA = $00100000; + IF_ARM32 = $00010000; + IF_THUMB = $00020000; + IF_THUMB32 = $00040000; + IF_WIDE = $00080000; + + IF_ARMvMASK = $0FF00000; + IF_ARMv4 = $00100000; + IF_ARMv4T = $00200000; + IF_ARMv5 = $00300000; + IF_ARMv5T = $00400000; + IF_ARMv5TE = $00500000; + IF_ARMv5TEJ = $00600000; + IF_ARMv6 = $00700000; + IF_ARMv6K = $00800000; + IF_ARMv6T2 = $00900000; + IF_ARMv6Z = $00A00000; + IF_ARMv6M = $00B00000; + IF_ARMv7 = $00C00000; + IF_ARMv7A = $00D00000; + IF_ARMv7R = $00E00000; + IF_ARMv7M = $00F00000; + IF_ARMv7EM = $01000000; + + IF_FPMASK = $F0000000; + IF_FPA = $10000000; + IF_VFPv2 = $20000000; + IF_VFPv3 = $40000000; + IF_VFPv4 = $80000000; { if the instruction can change in a second pass } IF_PASS2 = longint($80000000); @@ -142,9 +177,9 @@ uses tinsentry = record opcode : tasmop; ops : byte; - optypes : array[0..3] of longint; + optypes : array[0..5] of longint; code : array[0..maxinfolen] of char; - flags : longint; + flags : longword; end; pinsentry=^tinsentry; @@ -228,11 +263,18 @@ uses procedure ppubuildderefimploper(var o:toper);override; procedure ppuderefoper(var o:toper);override; private + { pass1 info } + inIT, + lastinIT: boolean; + { arm version info } + fArmVMask, + fArmMask : longint; { next fields are filled in pass1, so pass2 is faster } inssize : shortint; insoffset : longint; LastInsOffset : longint; { need to be public to be reset } insentry : PInsEntry; + procedure BuildArmMasks; function InsEnd:longint; procedure create_ot(objdata:TObjData); function Matches(p:PInsEntry):longint; @@ -247,10 +289,6 @@ uses { nothing to add } end; - tai_thumb_func = class(tai) - constructor create; - end; - function spilling_create_load(const ref:treference;r:tregister):Taicpu; function spilling_create_store(r:tregister; const ref:treference):Taicpu; @@ -614,9 +652,10 @@ implementation result:=( ((opcode=A_MOV) and (regtype = R_INTREGISTER)) or ((opcode=A_MVF) and (regtype = R_FPUREGISTER)) or - ((opcode in [A_FCPYS, A_FCPYD]) and (regtype = R_MMREGISTER)) + ((opcode in [A_FCPYS, A_FCPYD]) and (regtype = R_MMREGISTER)) or + ((opcode in [A_VMOV]) and (regtype = R_MMREGISTER) and (oppostfix in [PF_F32,PF_F64])) ) and - (oppostfix in [PF_None,PF_D]) and + ((oppostfix in [PF_None,PF_D]) or (opcode = A_VMOV)) and (condition=C_None) and (ops=2) and (oper[0]^.typ=top_reg) and @@ -626,8 +665,6 @@ implementation function spilling_create_load(const ref:treference;r:tregister):Taicpu; - var - op: tasmop; begin case getregtype(r) of R_INTREGISTER : @@ -638,19 +675,7 @@ implementation } result:=taicpu.op_reg_const_ref(A_LFM,r,1,ref); R_MMREGISTER : - begin - case getsubreg(r) of - R_SUBFD: - op:=A_FLDD; - R_SUBFS: - op:=A_FLDS; - R_SUBNONE: - op:=A_VLDR; - else - internalerror(2009112905); - end; - result:=taicpu.op_reg_ref(op,r,ref); - end; + result:=taicpu.op_reg_ref(A_VLDR,r,ref); else internalerror(200401041); end; @@ -658,8 +683,6 @@ implementation function spilling_create_store(r:tregister; const ref:treference):Taicpu; - var - op: tasmop; begin case getregtype(r) of R_INTREGISTER : @@ -670,19 +693,7 @@ implementation } result:=taicpu.op_reg_const_ref(A_SFM,r,1,ref); R_MMREGISTER : - begin - case getsubreg(r) of - R_SUBFD: - op:=A_FSTD; - R_SUBFS: - op:=A_FSTS; - R_SUBNONE: - op:=A_VSTR; - else - internalerror(2009112904); - end; - result:=taicpu.op_reg_ref(op,r,ref); - end; + result:=taicpu.op_reg_ref(A_VSTR,r,ref); else internalerror(200401041); end; @@ -1302,6 +1313,41 @@ implementation end; end; + curtai:=tai(curtai.Next); + end; + end; + + + procedure ensurethumbencodings(list: TAsmList); + var + curtai: tai; + op2reg: TRegister; + begin + { Do Thumb 16bit transformations to form valid instruction forms } + curtai:=tai(list.first); + while assigned(curtai) do + begin + case curtai.typ of + ait_instruction: + begin + case taicpu(curtai).opcode of + A_ADD, + A_AND,A_EOR,A_ORR,A_BIC, + A_LSL,A_LSR,A_ASR,A_ROR, + A_ADC,A_SBC: + begin + if (taicpu(curtai).ops = 3) and + (taicpu(curtai).oper[2]^.typ=top_reg) and + (taicpu(curtai).oper[0]^.reg=taicpu(curtai).oper[1]^.reg) and + (taicpu(curtai).oper[0]^.reg<>NR_STACK_POINTER_REG) then + begin + taicpu(curtai).oper[1]^.reg:=taicpu(curtai).oper[2]^.reg; + taicpu(curtai).ops:=2; + end; + end; + end; + end; + end; curtai:=tai(curtai.Next); end; @@ -1401,14 +1447,175 @@ implementation end; end; + procedure fix_invalid_imms(list: TAsmList); + var + curtai: tai; + sh: byte; + begin + curtai:=tai(list.First); + while assigned(curtai) do + begin + case curtai.typ of + ait_instruction: + begin + if (taicpu(curtai).opcode in [A_AND,A_BIC]) and + (taicpu(curtai).ops=3) and + (taicpu(curtai).oper[2]^.typ=top_const) and + (not is_shifter_const(taicpu(curtai).oper[2]^.val,sh)) and + is_shifter_const((not taicpu(curtai).oper[2]^.val) and $FFFFFFFF,sh) then + begin + case taicpu(curtai).opcode of + A_AND: taicpu(curtai).opcode:=A_BIC; + A_BIC: taicpu(curtai).opcode:=A_AND; + end; + taicpu(curtai).oper[2]^.val:=(not taicpu(curtai).oper[2]^.val) and $FFFFFFFF; + end + else if (taicpu(curtai).opcode in [A_SUB,A_ADD]) and + (taicpu(curtai).ops=3) and + (taicpu(curtai).oper[2]^.typ=top_const) and + (not is_shifter_const(taicpu(curtai).oper[2]^.val,sh)) and + is_shifter_const(-taicpu(curtai).oper[2]^.val,sh) then + begin + case taicpu(curtai).opcode of + A_ADD: taicpu(curtai).opcode:=A_SUB; + A_SUB: taicpu(curtai).opcode:=A_ADD; + end; + taicpu(curtai).oper[2]^.val:=-taicpu(curtai).oper[2]^.val; + end; + end; + end; + + curtai:=tai(curtai.Next); + end; + end; + + + procedure gather_it_info(list: TAsmList); + var + curtai: tai; + in_it: boolean; + it_count: longint; + begin + in_it:=false; + it_count:=0; + + curtai:=tai(list.First); + while assigned(curtai) do + begin + case curtai.typ of + ait_instruction: + begin + case taicpu(curtai).opcode of + A_IT..A_ITTTT: + begin + if in_it then + Message1(asmw_e_invalid_opcode_and_operands, 'ITxx instruction is inside another ITxx instruction') + else + begin + in_it:=true; + it_count:=GetITLevels(taicpu(curtai).opcode); + end; + end; + else + begin + taicpu(curtai).inIT:=in_it; + taicpu(curtai).lastinIT:=in_it and (it_count=1); + + if in_it then + begin + dec(it_count); + if it_count <= 0 then + in_it:=false; + end; + end; + end; + end; + end; + + curtai:=tai(curtai.Next); + end; + end; + + + { Expands pseudo instructions ( mov r1,r2,lsl #4 -> lsl r1,r2,#4) } + procedure expand_instructions(list: TAsmList); + var + curtai: tai; + begin + curtai:=tai(list.First); + while assigned(curtai) do + begin + case curtai.typ of + ait_instruction: + begin + case taicpu(curtai).opcode of + A_MOV: + begin + if (taicpu(curtai).ops=3) and + (taicpu(curtai).oper[2]^.typ=top_shifterop) then + begin + case taicpu(curtai).oper[2]^.shifterop^.shiftmode of + SM_LSL: taicpu(curtai).opcode:=A_LSL; + SM_LSR: taicpu(curtai).opcode:=A_LSR; + SM_ASR: taicpu(curtai).opcode:=A_ASR; + SM_ROR: taicpu(curtai).opcode:=A_ROR; + SM_RRX: taicpu(curtai).opcode:=A_RRX; + end; + + if taicpu(curtai).oper[2]^.shifterop^.shiftmode=SM_RRX then + taicpu(curtai).ops:=2; + + if taicpu(curtai).oper[2]^.shifterop^.rs=NR_NO then + taicpu(curtai).loadconst(2, taicpu(curtai).oper[2]^.shifterop^.shiftimm) + else + taicpu(curtai).loadreg(2, taicpu(curtai).oper[2]^.shifterop^.rs); + end; + end; + A_NEG: + begin + taicpu(curtai).opcode:=A_RSB; + + if taicpu(curtai).ops=2 then + begin + taicpu(curtai).loadconst(2,0); + taicpu(curtai).ops:=3; + end + else + begin + taicpu(curtai).loadconst(1,0); + taicpu(curtai).ops:=2; + end; + end; + A_SWI: + begin + taicpu(curtai).opcode:=A_SVC; + end; + end; + end; + end; + + curtai:=tai(curtai.Next); + end; + end; + + procedure finalizearmcode(list, listtoinsert: TAsmList); begin + expand_instructions(list); + { Do Thumb-2 16bit -> 32bit transformations } if GenerateThumb2Code then begin + ensurethumbencodings(list); ensurethumb2encodings(list); foldITInstructions(list); - end; + end + else if GenerateThumbCode then + ensurethumbencodings(list); + + gather_it_info(list); + + fix_invalid_imms(list); insertpcrelativedata(list, listtoinsert); end; @@ -1604,6 +1811,12 @@ implementation else if (ot and OT_FPUREG)=OT_FPUREG then s:=s+'fpureg' + else + if (ot and OT_REGS)=OT_REGS then + s:=s+'sreg' + else + if (ot and OT_REGF)=OT_REGF then + s:=s+'creg' else if (ot and OT_REGISTER)=OT_REGISTER then begin @@ -1628,9 +1841,17 @@ implementation s:=s+'mem'; addsize:=true; if (ot and OT_AM2)<>0 then + s:=s+' am2 ' + else if (ot and OT_AM6)<>0 then s:=s+' am2 '; end else + if (ot and OT_SHIFTEROP)=OT_SHIFTEROP then + begin + s:=s+'shifterop'; + addsize:=false; + end + else s:=s+'???'; { size } if addsize then @@ -1705,7 +1926,12 @@ implementation current_filepos:=fileinfo; { tranlate LDR+postfix to complete opcode } - if (opcode=A_LDR) and (oppostfix<>PF_None) then + if (opcode=A_LDR) and (oppostfix=PF_D) then + begin + opcode:=A_LDRD; + oppostfix:=PF_None; + end + else if (opcode=A_LDR) and (oppostfix<>PF_None) then begin if (oppostfix in [low(ldr2op)..high(ldr2op)]) then opcode:=ldr2op[oppostfix] @@ -1716,6 +1942,11 @@ implementation { postfix has been added to opcode } oppostfix:=PF_None; end + else if (opcode=A_STR) and (oppostfix=PF_D) then + begin + opcode:=A_STRD; + oppostfix:=PF_None; + end else if (opcode=A_STR) and (oppostfix<>PF_None) then begin if (oppostfix in [low(str2op)..high(str2op)]) then @@ -1771,6 +2002,58 @@ implementation end; + procedure taicpu.BuildArmMasks; + const + Masks: array[tcputype] of longint = + ( + IF_NONE, + IF_ARMv4, + IF_ARMv4, + IF_ARMv4T or IF_ARMv4, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z, + IF_ARMv4T or IF_ARMv5T or IF_ARMv6M, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7 or IF_ARMv7A, + IF_ARMv4T or IF_ARMv4 or IF_ARMv5 or IF_ARMv5T or IF_ARMv5TE or IF_ARMv5TEJ or IF_armv6 or IF_ARMv6K or IF_ARMv6T2 or IF_ARMv6Z or IF_ARMv7 or IF_ARMv7A or IF_ARMv7R, + IF_ARMv4T or IF_ARMv5T or IF_ARMv6T2 or IF_ARMv7M, + IF_ARMv4T or IF_ARMv5T or IF_ARMv6T2 or IF_ARMv7M or IF_ARMv7EM + ); + + FPUMasks: array[tfputype] of longword = + ( + IF_NONE, + IF_NONE, + IF_NONE, + IF_FPA, + IF_FPA, + IF_FPA, + IF_VFPv2, + IF_VFPv2 or IF_VFPv3, + IF_VFPv2 or IF_VFPv3, + IF_NONE, + IF_VFPv2 or IF_VFPv3 or IF_VFPv4 + ); + begin + fArmVMask:=Masks[current_settings.cputype] or FPUMasks[current_settings.fputype]; + + if current_settings.instructionset=is_thumb then + begin + fArmMask:=IF_THUMB; + if CPUARM_HAS_THUMB2 in cpu_capabilities[current_settings.cputype] then + fArmMask:=fArmMask or IF_THUMB32; + end + else + fArmMask:=IF_ARM32; + end; + + function taicpu.InsEnd:longint; begin Result:=0; { unimplemented } @@ -1798,9 +2081,19 @@ implementation begin case getregtype(reg) of R_INTREGISTER: - ot:=OT_REG32 or OT_SHIFTEROP; + begin + ot:=OT_REG32 or OT_SHIFTEROP; + if getsupreg(reg)<8 then + ot:=ot or OT_REGLO + else if reg=NR_STACK_POINTER_REG then + ot:=ot or OT_REGSP; + end; R_FPUREGISTER: ot:=OT_FPUREG; + R_MMREGISTER: + ot:=OT_VREG; + R_SPECIALREGISTER: + ot:=OT_REGF; else internalerror(2005090901); end; @@ -1831,7 +2124,30 @@ implementation ref^.base:=NR_PC; { determine possible address modes } + if GenerateThumbCode or + GenerateThumb2Code then + begin + if (ref^.base=NR_PC) then + ot:=ot or OT_AM6 + else if (ref^.base=NR_STACK_POINTER_REG) then + ot:=ot or OT_AM5 + else if ref^.index=NR_NO then + ot:=ot or OT_AM4 + else + ot:=ot or OT_AM3; + end; + if (ref^.base<>NR_NO) and + (opcode in [A_LDREX,A_LDREXB,A_LDREXH,A_LDREXD, + A_STREX,A_STREXB,A_STREXH,A_STREXD]) and + ( + (ref^.addressmode=AM_OFFSET) and + (ref^.index=NR_NO) and + (ref^.shiftmode=SM_None) and + (ref^.offset=0) + ) then + ot:=ot or OT_AM6 + else if (ref^.base<>NR_NO) and ( ( (ref^.index=NR_NO) and @@ -1846,14 +2162,17 @@ implementation ( (ref^.index<>NR_NO) and (ref^.shiftmode<>SM_None) and - (ref^.shiftimm<=31) and + (ref^.shiftimm<=32) and (ref^.offset=0) ) ) then ot:=ot or OT_AM2; if (ref^.index<>NR_NO) and - (oppostfix in [PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA]) and + (oppostfix in [PF_None,PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA, + PF_IAD,PF_DBD,PF_FDD,PF_EAD, + PF_IAS,PF_DBS,PF_FDS,PF_EAS, + PF_IAX,PF_DBX,PF_FDX,PF_EAX]) and ( (ref^.base=NR_NO) and (ref^.shiftmode=SM_None) and @@ -1887,7 +2206,11 @@ implementation top_const : begin ot:=OT_IMMEDIATE; - if is_shifter_const(val,dummy) then + if (val=0) then + ot:=ot_immediatezero + else if is_shifter_const(val,dummy) then + ot:=OT_IMMSHIFTER + else if GenerateThumb2Code and is_thumb32_imm(val) then ot:=OT_IMMSHIFTER else ot:=OT_IMM32 @@ -1902,6 +2225,18 @@ implementation begin ot:=OT_SHIFTEROP; end; + top_conditioncode: + begin + ot:=OT_CONDITION; + end; + top_specialreg: + begin + ot:=OT_REGS; + end; + top_modeflags: + begin + ot:=OT_MODEFLAGS; + end; else internalerror(2004022623); end; @@ -1935,7 +2270,6 @@ implementation {siz : array[0..3] of longint;} begin Matches:=100; - writeln(getstring,'---'); { Check the opcode and operands } if (p^.opcode<>opcode) or (p^.ops<>ops) then @@ -1944,6 +2278,27 @@ implementation exit; end; + { check ARM instruction version } + if (p^.flags and fArmVMask)=0 then + begin + Matches:=0; + exit; + end; + + { check ARM instruction type } + if (p^.flags and fArmMask)=0 then + begin + Matches:=0; + exit; + end; + + { Check wideformat flag } + if wideformat and ((p^.flags and IF_WIDE)=0) then + begin + matches:=0; + exit; + end; + { Check that no spurious colons or TOs are present } for i:=0 to p^.ops-1 do if (oper[i]^.ot and (not p^.optypes[i]) and (OT_COLON or OT_TO))<>0 then @@ -1965,6 +2320,12 @@ implementation Matches:=0; exit; end + else if ((p^.optypes[i] and OT_OPT_SIZE)<>0) and + ((p^.optypes[i] and OT_OPT_SIZE)<>(oper[i]^.ot and OT_OPT_SIZE)) then + begin + Matches:=0; + exit; + end else Matches:=1; end; @@ -1977,7 +2338,7 @@ implementation { update condition flags or floating point single } if (oppostfix=PF_S) and - not(p^.code[0] in [#$04]) then + not(p^.code[0] in [#$04..#$0F,#$14..#$16,#$29,#$30,#$60..#$6B,#$80..#$82,#$A0..#$A2,#$44,#$94,#$42,#$92]) then begin Matches:=0; exit; @@ -1985,7 +2346,13 @@ implementation { floating point size } if (oppostfix in [PF_D,PF_E,PF_P,PF_EP]) and - not(p^.code[0] in []) then + not(p^.code[0] in [ + // FPA + #$A0..#$A2, + // old-school VFP + #$42,#$92, + // vldm/vstm + #$44,#$94]) then begin Matches:=0; exit; @@ -1997,7 +2364,9 @@ implementation // ldr,str,ldrb,strb #$17, // stm,ldm - #$26 + #$26,#$69,#$8C, + // vldm/vstm + #$44,#$94 ]) then begin Matches:=0; @@ -2017,6 +2386,57 @@ implementation exit; end; + { Check thumb flags } + if p^.code[0] in [#$60..#$61] then + begin + if (p^.code[0]=#$60) and + (GenerateThumb2Code and + ((not inIT) and (oppostfix<>PF_S)) or + (inIT and (condition=C_None))) then + begin + Matches:=0; + exit; + end + else if (p^.code[0]=#$61) and + (oppostfix=PF_S) then + begin + Matches:=0; + exit; + end; + end + else if p^.code[0]=#$62 then + begin + if (GenerateThumb2Code and + (condition<>C_None) and + (not inIT) and + (not lastinIT)) then + begin + Matches:=0; + exit; + end; + end + else if p^.code[0]=#$63 then + begin + if inIT then + begin + Matches:=0; + exit; + end; + end + else if p^.code[0]=#$64 then + begin + if (opcode=A_MUL) then + begin + if (ops=3) and + ((oper[2]^.typ<>top_reg) or + (oper[0]^.reg<>oper[2]^.reg)) then + begin + matches:=0; + exit; + end; + end; + end; + { Check operand sizes } { as default an untyped size can get all the sizes, this is different from nasm, but else we need to do a lot checking which opcodes want @@ -2112,6 +2532,8 @@ implementation begin { create the .ot fields } create_ot(objdata); + + BuildArmMasks; { set the file postion } current_filepos:=fileinfo; end @@ -2148,1013 +2570,2895 @@ implementation procedure taicpu.gencode(objdata:TObjData); + const + CondVal : array[TAsmCond] of byte=( + $E, $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $A, + $B, $C, $D, $E, 0); var - bytes : dword; + bytes, rd, rm, rn, d, m, n : dword; + bytelen : longint; + dp_operation : boolean; i_field : byte; + currsym : TObjSymbol; + offset : longint; + refoper : poper; + msb : longint; + r: byte; procedure setshifterop(op : byte); + var + r : byte; + imm : dword; + count : integer; begin case oper[op]^.typ of top_const: begin i_field:=1; - bytes:=bytes or dword(oper[op]^.val and $fff); + if oper[op]^.val and $ff=oper[op]^.val then + bytes:=bytes or dword(oper[op]^.val) + else + begin + { calc rotate and adjust imm } + count:=0; + r:=0; + imm:=dword(oper[op]^.val); + repeat + imm:=RolDWord(imm, 2); + inc(r); + inc(count); + if count > 32 then + begin + message1(asmw_e_invalid_opcode_and_operands, 'invalid shifter imm'); + exit; + end; + until (imm and $ff)=imm; + bytes:=bytes or (r shl 8) or imm; + end; end; top_reg: begin i_field:=0; - bytes:=bytes or (getsupreg(oper[op]^.reg) shl 16); + bytes:=bytes or getsupreg(oper[op]^.reg); { does a real shifter op follow? } - if (op+1<=op) and (oper[op+1]^.typ=top_shifterop) then - begin - end; + if (op+1SM_RRX then + bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 + else + bytes:=bytes or (3 shl 5); + if getregtype(rs) <> R_INVALIDREGISTER then + begin + bytes:=bytes or (1 shl 4); + bytes:=bytes or (getsupreg(rs) shl 8); + end + end; end; else internalerror(2005091103); end; end; - begin - bytes:=$0; - i_field:=0; - { evaluate and set condition code } - - { condition code allowed? } - - { setup rest of the instruction } - case insentry^.code[0] of - #$08: + function MakeRegList(reglist: tcpuregisterset): word; + var + i, w: word; + begin + result:=0; + w:=1; + for i:=RS_R0 to RS_R15 do begin - { set instruction code } - bytes:=bytes or (ord(insentry^.code[1]) shl 26); - bytes:=bytes or (ord(insentry^.code[2]) shl 21); - - { set destination } - bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); - - { create shifter op } - setshifterop(1); - - { set i field } - bytes:=bytes or (i_field shl 25); - - { set s if necessary } - if oppostfix=PF_S then - bytes:=bytes or (1 shl 20); + if i in reglist then + result:=result or w; + w:=w shl 1 end; - #$ff: - internalerror(2005091101); + end; + + function getcoproc(reg: tregister): byte; + begin + if reg=NR_p15 then + result:=15 else - internalerror(2005091102); + begin + Message1(asmw_e_invalid_opcode_and_operands,'Invalid coprocessor port'); + result:=0; + end; end; - { we're finished, write code } - objdata.writebytes(bytes,sizeof(bytes)); - end; + function getcoprocreg(reg: tregister): byte; + begin + result:=getsupreg(reg)-getsupreg(NR_CR0); + end; -{$ifdef dummy} -(* -static void gencode (long segment, long offset, int bits, - insn *ins, char *codes, long insn_end) -{ - int has_S_code; /* S - setflag */ - int has_B_code; /* B - setflag */ - int has_T_code; /* T - setflag */ - int has_W_code; /* ! => W flag */ - int has_F_code; /* ^ => S flag */ - int keep; - unsigned char c; - unsigned char bytes[4]; - long data, size; - static int cc_code[] = /* bit pattern of cc */ - { /* order as enum in */ - 0x0E, 0x03, 0x02, 0x00, /* nasm.h */ - 0x0A, 0x0C, 0x08, 0x0D, - 0x09, 0x0B, 0x04, 0x01, - 0x05, 0x07, 0x06, - }; - - -#ifdef DEBUG -static char *CC[] = - { /* condition code names */ - "AL", "CC", "CS", "EQ", - "GE", "GT", "HI", "LE", - "LS", "LT", "MI", "NE", - "PL", "VC", "VS", "", - "S" -}; - - - has_S_code = (ins->condition & C_SSETFLAG); - has_B_code = (ins->condition & C_BSETFLAG); - has_T_code = (ins->condition & C_TSETFLAG); - has_W_code = (ins->condition & C_EXSETFLAG); - has_F_code = (ins->condition & C_FSETFLAG); - ins->condition = (ins->condition & 0x0F); - - - if (rt_debug) - { - printf ("gencode: instruction: %s%s", insn_names[ins->opcode], - CC[ins->condition & 0x0F]); - if (has_S_code) - printf ("S"); - if (has_B_code) - printf ("B"); - if (has_T_code) - printf ("T"); - if (has_W_code) - printf ("!"); - if (has_F_code) - printf ("^"); - - printf ("\n"); - - c = *codes; - - printf (" (%d) decode - '0x%02X'\n", ins->operands, c); - - - bytes[0] = 0xB; - bytes[1] = 0xE; - bytes[2] = 0xE; - bytes[3] = 0xF; - } + function getmmreg(reg: tregister): byte; + begin + case reg of + NR_D0: result:=0; + NR_D1: result:=1; + NR_D2: result:=2; + NR_D3: result:=3; + NR_D4: result:=4; + NR_D5: result:=5; + NR_D6: result:=6; + NR_D7: result:=7; + NR_D8: result:=8; + NR_D9: result:=9; + NR_D10: result:=10; + NR_D11: result:=11; + NR_D12: result:=12; + NR_D13: result:=13; + NR_D14: result:=14; + NR_D15: result:=15; + NR_D16: result:=16; + NR_D17: result:=17; + NR_D18: result:=18; + NR_D19: result:=19; + NR_D20: result:=20; + NR_D21: result:=21; + NR_D22: result:=22; + NR_D23: result:=23; + NR_D24: result:=24; + NR_D25: result:=25; + NR_D26: result:=26; + NR_D27: result:=27; + NR_D28: result:=28; + NR_D29: result:=29; + NR_D30: result:=30; + NR_D31: result:=31; + + NR_S0: result:=0; + NR_S1: result:=1; + NR_S2: result:=2; + NR_S3: result:=3; + NR_S4: result:=4; + NR_S5: result:=5; + NR_S6: result:=6; + NR_S7: result:=7; + NR_S8: result:=8; + NR_S9: result:=9; + NR_S10: result:=10; + NR_S11: result:=11; + NR_S12: result:=12; + NR_S13: result:=13; + NR_S14: result:=14; + NR_S15: result:=15; + NR_S16: result:=16; + NR_S17: result:=17; + NR_S18: result:=18; + NR_S19: result:=19; + NR_S20: result:=20; + NR_S21: result:=21; + NR_S22: result:=22; + NR_S23: result:=23; + NR_S24: result:=24; + NR_S25: result:=25; + NR_S26: result:=26; + NR_S27: result:=27; + NR_S28: result:=28; + NR_S29: result:=29; + NR_S30: result:=30; + NR_S31: result:=31; + else + result:=0; + end; + end; - // First condition code in upper nibble - if (ins->condition < C_NONE) - { - c = cc_code[ins->condition] << 4; - } - else - { - c = cc_code[C_AL] << 4; // is often ALWAYS but not always - } + procedure encodethumbimm(imm: longword); + var + imm12, tmp: tcgint; + shift: integer; + found: boolean; + begin + found:=true; + if (imm and $FF) = imm then + imm12:=imm + else if ((imm shr 16)=(imm and $FFFF)) and + ((imm and $FF00FF00) = 0) then + imm12:=(imm and $ff) or ($1 shl 8) + else if ((imm shr 16)=(imm and $FFFF)) and + ((imm and $00FF00FF) = 0) then + imm12:=((imm shr 8) and $ff) or ($2 shl 8) + else if ((imm shr 16)=(imm and $FFFF)) and + (((imm shr 8) and $FF)=(imm and $FF)) then + imm12:=(imm and $ff) or ($3 shl 8) + else + begin + found:=false; + imm12:=0; + for shift:=1 to 31 do + begin + tmp:=RolDWord(imm,shift); + if ((tmp and $FF)=tmp) and + ((tmp and $80)=$80) then + begin + imm12:=(tmp and $7F) or (shift shl 7); + found:=true; + break; + end; + end; + end; + if found then + begin + bytes:=bytes or (imm12 and $FF); + bytes:=bytes or (((imm12 shr 8) and $7) shl 12); + bytes:=bytes or (((imm12 shr 11) and $1) shl 26); + end + else + Message1(asmw_e_value_exceeds_bounds, IntToStr(imm)); + end; - switch (keep = *codes) - { - case 1: - // B, BL - ++codes; - c |= *codes++; - bytes[0] = c; + procedure setthumbshift(op: byte; is_sat: boolean = false); + var + shift,typ: byte; + begin + shift:=0; + typ:=0; + case oper[op]^.shifterop^.shiftmode of + SM_LSL: begin typ:=0; shift:=oper[op]^.shifterop^.shiftimm; end; + SM_LSR: begin typ:=1; shift:=oper[op]^.shifterop^.shiftimm; if shift=32 then shift:=0; end; + SM_ASR: begin typ:=2; shift:=oper[op]^.shifterop^.shiftimm; if shift=32 then shift:=0; end; + SM_ROR: begin typ:=3; shift:=oper[op]^.shifterop^.shiftimm; if shift=0 then message(asmw_e_invalid_opcode_and_operands); end; + SM_RRX: begin typ:=3; shift:=0; end; + end; - if (ins->oprs[0].segment != segment) - { - // fais une relocation - c = 1; - data = 0; // Let the linker locate ?? - } + if is_sat then + begin + bytes:=bytes or ((typ and 1) shl 5); + bytes:=bytes or ((typ shr 1) shl 21); + end else - { - c = 0; - data = ins->oprs[0].offset - (offset + 8); - - if (data % 4) - { - errfunc (ERR_NONFATAL, "offset not aligned on 4 bytes"); - } - } + bytes:=bytes or (typ shl 4); + bytes:=bytes or (shift and $3) shl 6; + bytes:=bytes or ((shift and $1C) shr 2) shl 12; + end; - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } + begin + bytes:=$0; + bytelen:=4; + i_field:=0; + { evaluate and set condition code } + bytes:=bytes or (CondVal[condition] shl 28); - data = data >> 2; - bytes[1] = (data >> 16) & 0xFF; - bytes[2] = (data >> 8) & 0xFF; - bytes[3] = (data ) & 0xFF; + { condition code allowed? } - if (c == 1) - { -// out (offset, segment, &bytes[0], OUT_RAWDATA+1, NO_SEG, NO_SEG); - out (offset, segment, &bytes[0], OUT_REL3ADR+4, ins->oprs[0].segment, NO_SEG); - } - else - { - out (offset, segment, &bytes[0], OUT_RAWDATA+4, NO_SEG, NO_SEG); - } - return; - - case 2: - // SWI - ++codes; - c |= *codes++; - bytes[0] = c; - data = ins->oprs[0].offset; - bytes[1] = (data >> 16) & 0xFF; - bytes[2] = (data >> 8) & 0xFF; - bytes[3] = (data) & 0xFF; - out (offset, segment, &bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - case 3: - // BX - ++codes; - c |= *codes++; - bytes[0] = c; - bytes[1] = *codes++; - bytes[2] = *codes++; - bytes[3] = *codes++; - c = regval (&ins->oprs[0],1); - if (c == 15) // PC - { - errfunc (ERR_WARNING, "'BX' with R15 has undefined behaviour"); - } - else if (c > 15) - { - errfunc (ERR_NONFATAL, "Illegal register specified for 'BX'"); - } + { setup rest of the instruction } + case insentry^.code[0] of + #$01: // B/BL + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + { set offset } + if oper[0]^.typ=top_const then + bytes:=bytes or ((oper[0]^.val shr 2) and $ffffff) + else + begin + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if (currsym.bind<>AB_LOCAL) and (currsym.objsection<>objdata.CurrObjSec) then + begin + objdata.writereloc(oper[0]^.ref^.offset,0,currsym,RELOC_RELATIVE_24); + bytes:=bytes or $fffffe; // TODO: Not sure this is right, but it matches the output of gas + end + else + bytes:=bytes or (((currsym.offset-insoffset-8) shr 2) and $ffffff); + end; + end; + #$02: + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + { set code } + bytes:=bytes or (oper[0]^.val and $FFFFFF); + end; + #$03: + begin // BLX/BX + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + + bytes:=bytes or getsupreg(oper[0]^.reg); + end; + #$04..#$07: // SUB + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + { set Rn } + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + { create shifter op } + setshifterop(2); + { set I field } + bytes:=bytes or (i_field shl 25); + { set S if necessary } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$08,#$0A,#$0B: // MOV + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + { create shifter op } + setshifterop(1); + { set I field } + bytes:=bytes or (i_field shl 25); + { set S if necessary } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$0C,#$0E,#$0F: // CMP + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + { create shifter op } + setshifterop(1); + { set I field } + bytes:=bytes or (i_field shl 25); + { always set S bit } + bytes:=bytes or (1 shl 20); + end; + #$10: // MRS + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + + case oper[1]^.reg of + NR_APSR,NR_CPSR:; + NR_SPSR: + begin + bytes:=bytes or (1 shl 22); + end; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end; + #$12,#$13: // MSR + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + { set destination } + + if oper[0]^.typ=top_specialreg then + begin + if (oper[0]^.specialreg<>NR_CPSR) and + (oper[0]^.specialreg<>NR_SPSR) then + Message1(asmw_e_invalid_opcode_and_operands, '"Invalid special reg"'); + + if srC in oper[0]^.specialflags then + bytes:=bytes or (1 shl 16); + if srX in oper[0]^.specialflags then + bytes:=bytes or (1 shl 17); + if srS in oper[0]^.specialflags then + bytes:=bytes or (1 shl 18); + if srF in oper[0]^.specialflags then + bytes:=bytes or (1 shl 19); + + { Set R bit } + if oper[0]^.specialreg=NR_SPSR then + bytes:=bytes or (1 shl 22); + end + else + case oper[0]^.reg of + NR_APSR_nzcvq: bytes:=bytes or (2 shl 18); + NR_APSR_g: bytes:=bytes or (1 shl 18); + NR_APSR_nzcvqg: bytes:=bytes or (3 shl 18); + else + Message1(asmw_e_invalid_opcode_and_operands, 'Invalid combination APSR bits used'); + end; + + setshifterop(1); + end; + #$14: // MUL/MLA r1,r2,r3 + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]); + { set regs } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 16; + bytes:=bytes or getsupreg(oper[1]^.reg); + bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; + + if oppostfix in [PF_S] then + bytes:=bytes or (1 shl 20); + end; + #$15: // MUL/MLA r1,r2,r3,r4 + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 16; + bytes:=bytes or getsupreg(oper[1]^.reg); + bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; + if ops>3 then + bytes:=bytes or getsupreg(oper[3]^.reg) shl 12 + else + bytes:=bytes or ord(insentry^.code[4]) shl 12; + + if oppostfix in [PF_R,PF_X] then + bytes:=bytes or (1 shl 5); + + if oppostfix in [PF_S] then + bytes:=bytes or (1 shl 20); + end; + #$16: // MULL r1,r2,r3,r4 + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + + if (ops=3) and (opcode=A_PKHTB) then + begin + bytes:=bytes or getsupreg(oper[1]^.reg); + bytes:=bytes or getsupreg(oper[2]^.reg) shl 16; + end + else + begin + bytes:=bytes or getsupreg(oper[1]^.reg) shl 16; + bytes:=bytes or getsupreg(oper[2]^.reg); + end; + + if ops=4 then + begin + if oper[3]^.typ=top_shifterop then + begin + if opcode in [A_PKHBT,A_PKHTB] then + begin + if ((opcode=A_PKHTB) and + (oper[3]^.shifterop^.shiftmode <> SM_ASR)) or + ((opcode=A_PKHBT) and + (oper[3]^.shifterop^.shiftmode <> SM_LSL)) or + (oper[3]^.shifterop^.rs<>NR_NO) then + Message1(asmw_e_invalid_opcode_and_operands,GetString); + + bytes:=bytes or ((oper[3]^.shifterop^.shiftimm and $1F) shl 7); + end + else + begin + if (oper[3]^.shifterop^.shiftmode<>sm_ror) or + (oper[3]^.shifterop^.rs<>NR_NO) or + (not (oper[3]^.shifterop^.shiftimm in [0,8,16,24])) then + Message1(asmw_e_invalid_opcode_and_operands,GetString); + + bytes:=bytes or (((oper[3]^.shifterop^.shiftimm shr 3) and $3) shl 10); + end; + end + else + bytes:=bytes or getsupreg(oper[3]^.reg) shl 8; + end; + + if PF_S=oppostfix then + bytes:=bytes or (1 shl 20); + if PF_X=oppostfix then + bytes:=bytes or (1 shl 5); + end; + #$17: // LDR/STR + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[1]^.ref^.offset; + if offset>=0 then + { set U flag } + bytes:=bytes or (1 shl 23) + else + offset:=-offset; + bytes:=bytes or (offset and $FFF); + end + else + begin + { set U flag } + if oper[1]^.ref^.signindex>=0 then + bytes:=bytes or (1 shl 23); + { set I flag } + bytes:=bytes or (1 shl 25); + bytes:=bytes or getsupreg(oper[1]^.ref^.index); + { set shift } + with oper[1]^.ref^ do + if shiftmode<>SM_None then + begin + bytes:=bytes or ((shiftimm and $1F) shl 7); + if shiftmode<>SM_RRX then + bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 + else + bytes:=bytes or (3 shl 5); + end + end; + { set W bit } + if oper[1]^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 21); + { set P bit if necessary } + if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then + bytes:=bytes or (1 shl 24); + end; + #$18: // LDREX/STREX + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + if (ops=3) then + begin + if opcode<>A_LDREXD then + bytes:=bytes or getsupreg(oper[1]^.reg); + + bytes:=bytes or (getsupreg(oper[2]^.ref^.base) shl 16); + end + else if (ops=4) then // STREXD + begin + if opcode<>A_LDREXD then + bytes:=bytes or getsupreg(oper[1]^.reg); + + bytes:=bytes or (getsupreg(oper[3]^.ref^.base) shl 16); + end + else + bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 16); + end; + #$19: // LDRD/STRD + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + + refoper:=oper[1]; + if ops=3 then + refoper:=oper[2]; + + bytes:=bytes or getsupreg(refoper^.ref^.base) shl 16; + if getregtype(refoper^.ref^.index)=R_INVALIDREGISTER then + begin + bytes:=bytes or (1 shl 22); + { set offset } + offset:=0; + currsym:=objdata.symbolref(refoper^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+refoper^.ref^.offset; + if offset>=0 then + { set U flag } + bytes:=bytes or (1 shl 23) + else + offset:=-offset; + bytes:=bytes or (offset and $F); + bytes:=bytes or ((offset and $F0) shl 4); + end + else + begin + { set U flag } + if refoper^.ref^.signindex>=0 then + bytes:=bytes or (1 shl 23); + bytes:=bytes or getsupreg(refoper^.ref^.index); + end; + { set W bit } + if refoper^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 21); + { set P bit if necessary } + if refoper^.ref^.addressmode<>AM_POSTINDEXED then + bytes:=bytes or (1 shl 24); + end; + #$1A: // QADD/QSUB + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[1]^.reg) shl 0; + bytes:=bytes or getsupreg(oper[2]^.reg) shl 16; + end; + #$1B: + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[1]^.reg); + if ops=3 then + begin + if (oper[2]^.shifterop^.shiftmode<>sm_ror) or + (oper[2]^.shifterop^.rs<>NR_NO) or + (not (oper[2]^.shifterop^.shiftimm in [0,8,16,24])) then + Message1(asmw_e_invalid_opcode_and_operands,GetString); + + bytes:=bytes or (((oper[2]^.shifterop^.shiftimm shr 3) and $3) shl 10); + end; + end; + #$1C: // MCR/MRC + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs and operands } + bytes:=bytes or getcoproc(oper[0]^.reg) shl 8; + bytes:=bytes or ((oper[1]^.val and $7) shl 21); + bytes:=bytes or getsupreg(oper[2]^.reg) shl 12; + bytes:=bytes or getcoprocreg(oper[3]^.reg) shl 16; + bytes:=bytes or getcoprocreg(oper[4]^.reg); + if ops > 5 then + bytes:=bytes or ((oper[5]^.val and $7) shl 5); + end; + #$1D: // MCRR/MRRC + begin + { set instruction code } + bytes:=bytes or ord(insentry^.code[1]) shl 24; + bytes:=bytes or ord(insentry^.code[2]) shl 16; + bytes:=bytes or ord(insentry^.code[3]) shl 4; + { set regs and operands } + bytes:=bytes or getcoproc(oper[0]^.reg) shl 8; + bytes:=bytes or ((oper[1]^.val and $7) shl 4); + bytes:=bytes or getsupreg(oper[2]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[3]^.reg) shl 16; + bytes:=bytes or getcoprocreg(oper[4]^.reg); + end; + #$1E: // LDRHT/STRHT + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + + refoper:=oper[1]; + + bytes:=bytes or getsupreg(refoper^.ref^.base) shl 16; + if getregtype(refoper^.ref^.index)=R_INVALIDREGISTER then + begin + bytes:=bytes or (1 shl 22); + { set offset } + offset:=0; + currsym:=objdata.symbolref(refoper^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+refoper^.ref^.offset; + + if offset>=0 then + { set U flag } + bytes:=bytes or (1 shl 23) + else + offset:=-offset; + bytes:=bytes or (offset and $F); + bytes:=bytes or ((offset and $F0) shl 4); + end + else + begin + { set U flag } + if refoper^.ref^.signindex>=0 then + bytes:=bytes or (1 shl 23); + bytes:=bytes or getsupreg(refoper^.ref^.index); + end; + end; + #$22: // LDRH/STRH + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 16); + bytes:=bytes or ord(insentry^.code[2]); + { src/dest register (Rd) } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + { base register (Rn) } + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then + begin + bytes:=bytes or (1 shl 22); // with immediate offset + offset:=oper[1]^.ref^.offset; + if offset>=0 then + { set U flag } + bytes:=bytes or (1 shl 23) + else + offset:=-offset; + bytes:=bytes or (offset and $F); + bytes:=bytes or ((offset and $F0) shl 4); + end + else + begin + { set U flag } + if oper[1]^.ref^.signindex>=0 then + bytes:=bytes or (1 shl 23); + bytes:=bytes or getsupreg(oper[1]^.ref^.index); + end; + { set W bit } + if oper[1]^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 21); + { set P bit if necessary } + if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then + bytes:=bytes or (1 shl 24); + end; + #$25: // PLD/PLI + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; + if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[0]^.ref^.offset; + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or offset + end + else + begin + offset:=-offset; + bytes:=bytes or offset + end; + end + else + begin + bytes:=bytes or (1 shl 25); + { set U flag } + if oper[0]^.ref^.signindex>=0 then + bytes:=bytes or (1 shl 23); + bytes:=bytes or getsupreg(oper[0]^.ref^.index); + { set shift } + with oper[0]^.ref^ do + if shiftmode<>SM_None then + begin + bytes:=bytes or ((shiftimm and $1F) shl 7); + if shiftmode<>SM_RRX then + bytes:=bytes or (ord(shiftmode) - ord(SM_LSL)) shl 5 + else + bytes:=bytes or (3 shl 5); + end + end; + end; + #$26: // LDM/STM + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 20); + + if ops>1 then + begin + if oper[0]^.typ=top_ref then + begin + { set W bit } + if oper[0]^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 21); + { set Rn } + bytes:=bytes or (getsupreg(oper[0]^.ref^.index) shl 16); + end + else { typ=top_reg } + begin + { set Rn } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + end; + + if oper[1]^.usermode then + begin + if (oper[0]^.typ=top_ref) then + begin + if (opcode=A_LDM) and + (RS_PC in oper[1]^.regset^) then + begin + // Valid exception return + end + else + Message(asmw_e_invalid_opcode_and_operands); + end; + + bytes:=bytes or (1 shl 22); + end; + { reglist } + bytes:=bytes or MakeRegList(oper[1]^.regset^); + end + else + begin + { push/pop } + { Set W and Rn to SP } + if opcode=A_PUSH then + bytes:=bytes or (1 shl 21); + bytes:=bytes or ($D shl 16); + { reglist } + bytes:=bytes or MakeRegList(oper[0]^.regset^); + end; + { set P bit } + if (opcode=A_LDM) and (oppostfix in [PF_ED,PF_EA,PF_IB,PF_DB]) + or (opcode=A_STM) and (oppostfix in [PF_FA,PF_FD,PF_IB,PF_DB]) + or (opcode=A_PUSH) then + bytes:=bytes or (1 shl 24); + { set U bit } + if (opcode=A_LDM) and (oppostfix in [PF_None,PF_ED,PF_FD,PF_IB,PF_IA]) + or (opcode=A_STM) and (oppostfix in [PF_None,PF_FA,PF_EA,PF_IB,PF_IA]) + or (opcode=A_POP) then + bytes:=bytes or (1 shl 23); + end; + #$27: // SWP/SWPB + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 20); + bytes:=bytes or (ord(insentry^.code[2]) shl 4); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or getsupreg(oper[1]^.reg); + if ops=3 then + bytes:=bytes or (getsupreg(oper[2]^.ref^.base) shl 16); + end; + #$28: // BX/BLX + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + { set offset } + if oper[0]^.typ=top_const then + bytes:=bytes or ((oper[0]^.val shr 2) and $ffffff) + else + begin + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if (currsym.bind<>AB_LOCAL) and (currsym.objsection<>objdata.CurrObjSec) then + begin + bytes:=bytes or $fffffe; // TODO: Not sure this is right, but it matches the output of gas + objdata.writereloc(oper[0]^.ref^.offset,0,currsym,RELOC_RELATIVE_24_THUMB); + end + else + begin + offset:=((currsym.offset-insoffset-8) and $3fffffe); + + { Turn BLX into BL if the destination isn't odd, could happen with recursion } + if not odd(offset shr 1) then + bytes:=(bytes and $EB000000) or $EB000000; + + bytes:=bytes or ((offset shr 2) and $ffffff); + bytes:=bytes or ((offset shr 1) and $1) shl 24; + end; + end; + end; + #$29: // SUB + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + { set S if necessary } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$2A: + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set opers } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + if opcode in [A_SSAT, A_SSAT16] then + bytes:=bytes or (((oper[1]^.val-1) and $1F) shl 16) + else + bytes:=bytes or ((oper[1]^.val and $1F) shl 16); + bytes:=bytes or getsupreg(oper[2]^.reg); + + if (ops>3) and + (oper[3]^.typ=top_shifterop) and + (oper[3]^.shifterop^.rs=NR_NO) then + begin + bytes:=bytes or ((oper[3]^.shifterop^.shiftimm and $1F) shl 7); + if oper[3]^.shifterop^.shiftmode=SM_ASR then + bytes:=bytes or (1 shl 6) + else if oper[3]^.shifterop^.shiftmode<>SM_LSL then + Message1(asmw_e_invalid_opcode_and_operands,GetString); + end; + end; + #$2B: // SETEND + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set endian specifier } + bytes:=bytes or ((oper[0]^.val and 1) shl 9); + end; + #$2C: // MOVW + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + { set imm } + bytes:=bytes or (oper[1]^.val and $FFF); + bytes:=bytes or ((oper[1]^.val and $F000) shl 4); + end; + #$2D: // BFX + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + + if ops=3 then + begin + msb:=(oper[1]^.val+oper[2]^.val-1); + + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + { set immediates } + bytes:=bytes or ((oper[1]^.val and $1F) shl 7); + bytes:=bytes or ((msb and $1F) shl 16); + end + else + begin + if opcode in [A_BFC,A_BFI] then + msb:=(oper[2]^.val+oper[3]^.val-1) + else + msb:=oper[3]^.val-1; + + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or getsupreg(oper[1]^.reg); + { set immediates } + bytes:=bytes or ((oper[2]^.val and $1F) shl 7); + bytes:=bytes or ((msb and $1F) shl 16); + end; + end; + #$2E: // Cache stuff + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set code } + bytes:=bytes or (oper[0]^.val and $F); + end; + #$2F: // Nop + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + end; + #$30: // Shifts + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set destination } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or getsupreg(oper[1]^.reg); + if ops>2 then + begin + { set shift } + if oper[2]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 8) + else + bytes:=bytes or ((oper[2]^.val and $1F) shl 7); + end; + { set S if necessary } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$31: // BKPT + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 0); + { set imm } + bytes:=bytes or (oper[0]^.val and $FFF0) shl 4; + bytes:=bytes or (oper[0]^.val and $F); + end; + #$32: // CLZ/REV + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or getsupreg(oper[1]^.reg); + end; + #$33: + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + + if oper[1]^.typ=top_ref then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[1]^.ref^.offset; + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or offset + end + else + begin + bytes:=bytes or (1 shl 22); + offset:=-offset; + bytes:=bytes or offset + end; + end + else + begin + if is_shifter_const(oper[1]^.val,r) then + begin + setshifterop(1); + bytes:=bytes or (1 shl 23); + end + else + begin + bytes:=bytes or (1 shl 22); + oper[1]^.val:=-oper[1]^.val; + setshifterop(1); + end; + end; + end; + #$40,#$90: // VMOV + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + + { set regs } + Rd:=0; + Rn:=0; + Rm:=0; + + case oppostfix of + PF_None: + begin + if ops=4 then + begin + if (getregtype(oper[0]^.reg)=R_MMREGISTER) and + (getregtype(oper[2]^.reg)=R_INTREGISTER) then + begin + Rd:=getmmreg(oper[0]^.reg); + Rm:=getsupreg(oper[2]^.reg); + Rn:=getsupreg(oper[3]^.reg); + end + else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and + (getregtype(oper[2]^.reg)=R_MMREGISTER) then + begin + Rm:=getsupreg(oper[0]^.reg); + Rn:=getsupreg(oper[1]^.reg); + Rd:=getmmreg(oper[2]^.reg); + end + else + message(asmw_e_invalid_opcode_and_operands); + + bytes:=bytes or (((Rd and $1E) shr 1) shl 0); + bytes:=bytes or ((Rd and $1) shl 5); + + bytes:=bytes or (Rm shl 12); + bytes:=bytes or (Rn shl 16); + end + else if ops=3 then + begin + if (getregtype(oper[0]^.reg)=R_MMREGISTER) and + (getregtype(oper[1]^.reg)=R_INTREGISTER) then + begin + Rd:=getmmreg(oper[0]^.reg); + Rm:=getsupreg(oper[1]^.reg); + Rn:=getsupreg(oper[2]^.reg); + end + else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and + (getregtype(oper[2]^.reg)=R_MMREGISTER) then + begin + Rm:=getsupreg(oper[0]^.reg); + Rn:=getsupreg(oper[1]^.reg); + Rd:=getmmreg(oper[2]^.reg); + end + else + message(asmw_e_invalid_opcode_and_operands); + + bytes:=bytes or ((Rd and $F) shl 0); + bytes:=bytes or ((Rd and $10) shl 1); + + bytes:=bytes or (Rm shl 12); + bytes:=bytes or (Rn shl 16); + end + else if ops=2 then + begin + if (getregtype(oper[0]^.reg)=R_MMREGISTER) and + (getregtype(oper[1]^.reg)=R_INTREGISTER) then + begin + Rd:=getmmreg(oper[0]^.reg); + Rm:=getsupreg(oper[1]^.reg); + end + else if (getregtype(oper[0]^.reg)=R_INTREGISTER) and + (getregtype(oper[1]^.reg)=R_MMREGISTER) then + begin + Rm:=getsupreg(oper[0]^.reg); + Rd:=getmmreg(oper[1]^.reg); + end + else + message(asmw_e_invalid_opcode_and_operands); + + bytes:=bytes or (((Rd and $1E) shr 1) shl 16); + bytes:=bytes or ((Rd and $1) shl 7); + + bytes:=bytes or (Rm shl 12); + end; + end; + PF_F32: + begin + if (getregtype(oper[0]^.reg)<>R_MMREGISTER) or + (getregtype(oper[1]^.reg)<>R_MMREGISTER) then + Message(asmw_e_invalid_opcode_and_operands); + + Rd:=getmmreg(oper[0]^.reg); + Rm:=getmmreg(oper[1]^.reg); + + bytes:=bytes or (((Rd and $1E) shr 1) shl 12); + bytes:=bytes or ((Rd and $1) shl 22); + + bytes:=bytes or (((Rm and $1E) shr 1) shl 0); + bytes:=bytes or ((Rm and $1) shl 5); + end; + PF_F64: + begin + if (getregtype(oper[0]^.reg)<>R_MMREGISTER) or + (getregtype(oper[1]^.reg)<>R_MMREGISTER) then + Message(asmw_e_invalid_opcode_and_operands); - bytes[3] |= (c & 0x0F); - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - case 4: // AND Rd,Rn,Rm - case 5: // AND Rd,Rn,Rm,Rs - case 6: // AND Rd,Rn,Rm,imm - case 7: // AND Rd,Rn,imm - ++codes; -#ifdef DEBUG - if (rt_debug) - { - printf (" decode - '0x%02X'\n", keep); - printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); - } -#endif - bytes[0] = c | *codes; - ++codes; - - bytes[1] = *codes; - if (has_S_code) - bytes[1] |= 0x10; - c = regval (&ins->oprs[1],1); - // Rn in low nibble - bytes[1] |= c; - - // Rd in high nibble - bytes[2] = regval (&ins->oprs[0],1) << 4; - - if (keep != 7) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[2],1); - } + Rd:=getmmreg(oper[0]^.reg); + Rm:=getmmreg(oper[1]^.reg); - // Shifts if any - if (keep == 5 || keep == 6) - { - // Shift in bytes 2 and 3 - if (keep == 5) - { - // Rs - c = regval (&ins->oprs[3],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 6) - { - c = (ins->oprs[3].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[3]) << 5; - - bytes[3] |= c; - } + bytes:=bytes or (1 shl 8); - // reg,reg,imm - if (keep == 7) - { - int shimm; + bytes:=bytes or ((Rd and $F) shl 12); + bytes:=bytes or (((Rd and $10) shr 4) shl 22); - shimm = imm_shift (ins->oprs[2].offset); + bytes:=bytes or (Rm and $F); + bytes:=bytes or ((Rm and $10) shl 1); + end; + end; + end; + #$41,#$91: // VMRS/VMSR + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set regs } + if (opcode=A_VMRS) or + (opcode=A_FMRX) then + begin + case oper[1]^.reg of + NR_FPSID: Rn:=$0; + NR_FPSCR: Rn:=$1; + NR_MVFR1: Rn:=$6; + NR_MVFR0: Rn:=$7; + NR_FPEXC: Rn:=$8; + else + Rn:=0; + message(asmw_e_invalid_opcode_and_operands); + end; - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } + bytes:=bytes or (Rn shl 16); - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; - - case 8: // MOV Rd,Rm - case 9: // MOV Rd,Rm,Rs - case 0xA: // MOV Rd,Rm,imm - case 0xB: // MOV Rd,imm - ++codes; -#ifdef DEBUG - if (rt_debug) - { - printf (" decode - '0x%02X'\n", keep); - printf (" code - '0x%02X'\n", (unsigned char) ( *codes)); - } -#endif - bytes[0] = c | *codes; - ++codes; + if oper[0]^.reg=NR_APSR_nzcv then + bytes:=bytes or ($F shl 12) + else + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + end + else + begin + case oper[0]^.reg of + NR_FPSID: Rn:=$0; + NR_FPSCR: Rn:=$1; + NR_FPEXC: Rn:=$8; + else + Rn:=0; + message(asmw_e_invalid_opcode_and_operands); + end; - bytes[1] = *codes; - if (has_S_code) - bytes[1] |= 0x10; + bytes:=bytes or (Rn shl 16); - // Rd in high nibble - bytes[2] = regval (&ins->oprs[0],1) << 4; + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 12); + end; + end; + #$42,#$92: // VMUL + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set regs } + if ops=3 then + begin + Rd:=getmmreg(oper[0]^.reg); + Rn:=getmmreg(oper[1]^.reg); + Rm:=getmmreg(oper[2]^.reg); + end + else if ops=1 then + begin + Rd:=getmmreg(oper[0]^.reg); + Rn:=0; + Rm:=0; + end + else if oper[1]^.typ=top_const then + begin + Rd:=getmmreg(oper[0]^.reg); + Rn:=0; + Rm:=0; + end + else + begin + Rd:=getmmreg(oper[0]^.reg); + Rn:=0; + Rm:=getmmreg(oper[1]^.reg); + end; - if (keep != 0x0B) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[1],1); - } + if (oppostfix=PF_F32) or (insentry^.code[5]=#1) then + begin + D:=rd and $1; Rd:=Rd shr 1; + N:=rn and $1; Rn:=Rn shr 1; + M:=rm and $1; Rm:=Rm shr 1; + end + else + begin + D:=(rd shr 4) and $1; Rd:=Rd and $F; + N:=(rn shr 4) and $1; Rn:=Rn and $F; + M:=(rm shr 4) and $1; Rm:=Rm and $F; - // Shifts if any - if (keep == 0x09 || keep == 0x0A) - { - // Shift in bytes 2 and 3 - if (keep == 0x09) - { - // Rs - c = regval (&ins->oprs[2],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 0x0A) - { - c = (ins->oprs[2].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[2]) << 5; - - bytes[3] |= c; - } + bytes:=bytes or (1 shl 8); + end; - // reg,imm - if (keep == 0x0B) - { - int shimm; + bytes:=bytes or (Rd shl 12); + bytes:=bytes or (Rn shl 16); + bytes:=bytes or (Rm shl 0); - shimm = imm_shift (ins->oprs[1].offset); + bytes:=bytes or (D shl 22); + bytes:=bytes or (N shl 7); + bytes:=bytes or (M shl 5); + end; + #$43,#$93: // VCVT + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set regs } + Rd:=getmmreg(oper[0]^.reg); + Rm:=getmmreg(oper[1]^.reg); + + if (ops=2) and + (oppostfix in [PF_F32F64,PF_F64F32]) then + begin + if oppostfix=PF_F32F64 then + begin + bytes:=bytes or (1 shl 8); - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } + D:=rd and $1; Rd:=Rd shr 1; + M:=(rm shr 4) and $1; Rm:=Rm and $F; + end + else + begin + D:=(rd shr 4) and $1; Rd:=Rd and $F; + M:=rm and $1; Rm:=Rm shr 1; + end; - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; + bytes:=bytes and $FFF0FFFF; + bytes:=bytes or ($7 shl 16); + bytes:=bytes or (Rd shl 12); + bytes:=bytes or (Rm shl 0); - case 0xC: // CMP Rn,Rm - case 0xD: // CMP Rn,Rm,Rs - case 0xE: // CMP Rn,Rm,imm - case 0xF: // CMP Rn,imm - ++codes; + bytes:=bytes or (D shl 22); + bytes:=bytes or (M shl 5); + end + else if (ops=2) and + (oppostfix=PF_None) then + begin + d:=0; + case getsubreg(oper[0]^.reg) of + R_SUBNONE: + rd:=getsupreg(oper[0]^.reg); + R_SUBFS: + begin + rd:=getmmreg(oper[0]^.reg); - bytes[0] = c | *codes++; + d:=rd and 1; + rd:=rd shr 1; + end; + R_SUBFD: + begin + rd:=getmmreg(oper[0]^.reg); - bytes[1] = *codes; + d:=(rd shr 4) and 1; + rd:=rd and $F; + end; + end; - // Implicit S code - bytes[1] |= 0x10; + m:=0; + case getsubreg(oper[1]^.reg) of + R_SUBNONE: + rm:=getsupreg(oper[1]^.reg); + R_SUBFS: + begin + rm:=getmmreg(oper[1]^.reg); - c = regval (&ins->oprs[0],1); - // Rn in low nibble - bytes[1] |= c; + m:=rm and 1; + rm:=rm shr 1; + end; + R_SUBFD: + begin + rm:=getmmreg(oper[1]^.reg); - // No destination - bytes[2] = 0; + m:=(rm shr 4) and 1; + rm:=rm and $F; + end; + end; - if (keep != 0x0B) - { - // Rm in low nibble - bytes[3] = regval (&ins->oprs[1],1); - } + bytes:=bytes or (Rd shl 12); + bytes:=bytes or (Rm shl 0); - // Shifts if any - if (keep == 0x0D || keep == 0x0E) - { - // Shift in bytes 2 and 3 - if (keep == 0x0D) - { - // Rs - c = regval (&ins->oprs[2],1); - bytes[2] |= c; - - c = 0x10; // Set bit 4 in byte[3] - } - if (keep == 0x0E) - { - c = (ins->oprs[2].offset) & 0x1F; - - // #imm - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - c = 0; // Clr bit 4 in byte[3] - } - // - c |= shiftval (&ins->oprs[2]) << 5; - - bytes[3] |= c; - } + bytes:=bytes or (D shl 22); + bytes:=bytes or (M shl 5); + end + else if ops=2 then + begin + case oppostfix of + PF_S32F64, + PF_U32F64, + PF_F64S32, + PF_F64U32: + bytes:=bytes or (1 shl 8); + end; - // reg,imm - if (keep == 0x0F) - { - int shimm; + if oppostfix in [PF_S32F32,PF_S32F64,PF_U32F32,PF_U32F64] then + begin + case oppostfix of + PF_S32F64, + PF_S32F32: + bytes:=bytes or (1 shl 16); + end; - shimm = imm_shift (ins->oprs[1].offset); + bytes:=bytes or (1 shl 18); - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } + D:=rd and $1; Rd:=Rd shr 1; - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); - return; + if oppostfix in [PF_S32F64,PF_U32F64] then + begin + M:=(rm shr 4) and $1; Rm:=Rm and $F; + end + else + begin + M:=rm and $1; Rm:=Rm shr 1; + end; + end + else + begin + case oppostfix of + PF_F64S32, + PF_F32S32: + bytes:=bytes or (1 shl 7); + else + bytes:=bytes and $FFFFFF7F; + end; - case 0x10: // MRS Rd, - ++codes; + M:=rm and $1; Rm:=Rm shr 1; - bytes[0] = c | *codes++; + if oppostfix in [PF_F64S32,PF_F64U32] then + begin + D:=(rd shr 4) and $1; Rd:=Rd and $F; + end + else + begin + D:=rd and $1; Rd:=Rd shr 1; + end + end; - bytes[1] = *codes++; + bytes:=bytes or (Rd shl 12); + bytes:=bytes or (Rm shl 0); - // Rd - c = regval (&ins->oprs[0],1); + bytes:=bytes or (D shl 22); + bytes:=bytes or (M shl 5); + end + else + begin + if rd<>rm then + message(asmw_e_invalid_opcode_and_operands); + + case oppostfix of + PF_S32F32,PF_U32F32, + PF_F32S32,PF_F32U32, + PF_S32F64,PF_U32F64, + PF_F64S32,PF_F64U32: + begin + if not (oper[2]^.val in [1..32]) then + message1(asmw_e_invalid_opcode_and_operands, 'fbits not within 1-32'); - bytes[2] = c << 4; + bytes:=bytes or (1 shl 7); + rn:=32; + end; + PF_S16F64,PF_U16F64, + PF_F64S16,PF_F64U16, + PF_S16F32,PF_U16F32, + PF_F32S16,PF_F32U16: + begin + if not (oper[2]^.val in [0..16]) then + message1(asmw_e_invalid_opcode_and_operands, 'fbits not within 0-16'); - bytes[3] = 0; + rn:=16; + end; + else + Rn:=0; + message(asmw_e_invalid_opcode_and_operands); + end; - c = ins->oprs[1].basereg; + case oppostfix of + PF_S16F64,PF_U16F64, + PF_S32F64,PF_U32F64, + PF_F64S16,PF_F64U16, + PF_F64S32,PF_F64U32: + begin + bytes:=bytes or (1 shl 8); + D:=(rd shr 4) and $1; Rd:=Rd and $F; + end; + else + begin + D:=rd and $1; Rd:=Rd shr 1; + end; + end; - if (c == R_CPSR || c == R_SPSR) - { - if (c == R_SPSR) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR or SPSR expected"); - } + case oppostfix of + PF_U16F64,PF_U16F32, + PF_U32F32,PF_U32F64, + PF_F64U16,PF_F32U16, + PF_F32U32,PF_F64U32: + bytes:=bytes or (1 shl 16); + end; - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); + if oppostfix in [PF_S32F32,PF_S32F64,PF_U32F32,PF_U32F64,PF_S16F32,PF_S16F64,PF_U16F32,PF_U16F64] then + bytes:=bytes or (1 shl 18); - return; + bytes:=bytes or (Rd shl 12); + bytes:=bytes or (D shl 22); - case 0x11: // MSR ,Rm - case 0x12: // MSR ,Rm - case 0x13: // MSR ,#expression - ++codes; + rn:=rn-oper[2]^.val; - bytes[0] = c | *codes++; + bytes:=bytes or ((rn and $1) shl 5); + bytes:=bytes or ((rn and $1E) shr 1); + end; + end; + #$44,#$94: // VLDM/VSTM/VPUSH/VPOP + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + { set regs } + if ops=2 then + begin + if oper[0]^.typ=top_ref then + begin + Rn:=getsupreg(oper[0]^.ref^.index); - bytes[1] = *codes++; + if oper[0]^.ref^.addressmode<>AM_OFFSET then + begin + { set W } + bytes:=bytes or (1 shl 21); + end + else if oppostfix in [PF_DB,PF_DBS,PF_DBD,PF_DBX] then + message1(asmw_e_invalid_opcode_and_operands, 'Invalid postfix without writeback'); + end + else + begin + Rn:=getsupreg(oper[0]^.reg); - bytes[2] = *codes; + if oppostfix in [PF_DB,PF_DBS,PF_DBD,PF_DBX] then + message1(asmw_e_invalid_opcode_and_operands, 'Invalid postfix without writeback'); + end; + bytes:=bytes or (Rn shl 16); - if (keep == 0x11 || keep == 0x12) - { - // Rm - c = regval (&ins->oprs[1],1); + { Set PU bits } + case oppostfix of + PF_None, + PF_IA,PF_IAS,PF_IAD,PF_IAX: + bytes:=bytes or (1 shl 23); + PF_DB,PF_DBS,PF_DBD,PF_DBX: + bytes:=bytes or (2 shl 23); + end; - bytes[3] = c; - } - else - { - int shimm; + case oppostfix of + PF_IAX,PF_DBX,PF_FDX,PF_EAX: + begin + bytes:=bytes or (1 shl 8); + bytes:=bytes or (1 shl 0); // Offset is odd + end; + end; - shimm = imm_shift (ins->oprs[1].offset); + dp_operation:=(oper[1]^.subreg=R_SUBFD); + if oper[1]^.regset^=[] then + message1(asmw_e_invalid_opcode_and_operands, 'Regset cannot be empty'); - if (shimm == -1) - { - errfunc (ERR_NONFATAL, "cannot create that constant"); - } - bytes[3] = shimm & 0xFF; - bytes[2] |= (shimm & 0xF00) >> 8; - } + rd:=0; + for r:=0 to 31 do + if r in oper[1]^.regset^ then + begin + rd:=r; + break; + end; - c = ins->oprs[0].basereg; - - if ( keep == 0x11) - { - if ( c == R_CPSR || c == R_SPSR) - { - if ( c== R_SPSR) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR or SPSR expected"); - } - } - else - { - if ( c == R_CPSR_FLG || c == R_SPSR_FLG) - { - if ( c== R_SPSR_FLG) - { - bytes[1] |= 0x40; - } - } - else - { - errfunc (ERR_NONFATAL, "CPSR_flg or SPSR_flg expected"); - } - } - break; + rn:=32-rd; + for r:=rd+1 to 31 do + if not(r in oper[1]^.regset^) then + begin + rn:=r-rd; + break; + end; - case 0x14: // MUL Rd,Rm,Rs - case 0x15: // MULA Rd,Rm,Rs,Rn - ++codes; + if dp_operation then + begin + bytes:=bytes or (1 shl 8); - bytes[0] = c | *codes++; + bytes:=bytes or (rn*2); - bytes[1] = *codes++; + bytes:=bytes or ((rd and $F) shl 12); + bytes:=bytes or (((rd and $10) shr 4) shl 22); + end + else + begin + bytes:=bytes or rn; - bytes[3] = *codes; + bytes:=bytes or ((rd and $1) shl 22); + bytes:=bytes or (((rd and $1E) shr 1) shl 12); + end; + end + else { VPUSH/VPOP } + begin + dp_operation:=(oper[0]^.subreg=R_SUBFD); + if oper[0]^.regset^=[] then + message1(asmw_e_invalid_opcode_and_operands, 'Regset cannot be empty'); - // Rd - bytes[1] |= regval (&ins->oprs[0],1); - if (has_S_code) - bytes[1] |= 0x10; + rd:=0; + for r:=0 to 31 do + if r in oper[0]^.regset^ then + begin + rd:=r; + break; + end; - // Rm - bytes[3] |= regval (&ins->oprs[1],1); + rn:=32-rd; + for r:=rd+1 to 31 do + if not(r in oper[0]^.regset^) then + begin + rn:=r-rd; + break; + end; - // Rs - bytes[2] = regval (&ins->oprs[2],1); + if dp_operation then + begin + bytes:=bytes or (1 shl 8); - if (keep == 0x15) - { - bytes[2] |= regval (&ins->oprs[3],1) << 4; - } - break; + bytes:=bytes or (rn*2); - case 0x16: // SMLAL RdHi,RdLo,Rm,Rs - ++codes; + bytes:=bytes or ((rd and $F) shl 12); + bytes:=bytes or (((rd and $10) shr 4) shl 22); + end + else + begin + bytes:=bytes or rn; - bytes[0] = c | *codes++; + bytes:=bytes or ((rd and $1) shl 22); + bytes:=bytes or (((rd and $1E) shr 1) shl 12); + end; + end; + end; + #$45,#$95: // VLDR/VSTR + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + { set regs } + rd:=getmmreg(oper[0]^.reg); - bytes[1] = *codes++; + if getsubreg(oper[0]^.reg)=R_SUBFD then + begin + bytes:=bytes or (1 shl 8); - bytes[3] = *codes; + bytes:=bytes or ((rd and $F) shl 12); + bytes:=bytes or (((rd and $10) shr 4) shl 22); + end + else + begin + bytes:=bytes or (((rd and $1E) shr 1) shl 12); + bytes:=bytes or ((rd and $1) shl 22); + end; - // RdHi - bytes[1] |= regval (&ins->oprs[1],1); - if (has_S_code) - bytes[1] |= 0x10; + { set ref } + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[1]^.ref^.offset; - // RdLo - bytes[2] = regval (&ins->oprs[0],1) << 4; - // Rm - bytes[3] |= regval (&ins->oprs[2],1); + offset:=offset div 4; - // Rs - bytes[2] |= regval (&ins->oprs[3],1); + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or offset + end + else + begin + offset:=-offset; + bytes:=bytes or offset + end; + end + else + message(asmw_e_invalid_opcode_and_operands); + end; + #$46: { System instructions } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + { set regs } + if (oper[0]^.typ=top_modeflags) then + begin + if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 8); + if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 7); + if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 6); + end; - break; + if (ops=2) then + bytes:=bytes or (oper[1]^.val and $1F) + else if (ops=1) and + (oper[0]^.typ=top_const) then + bytes:=bytes or (oper[0]^.val and $1F); + end; + #$60: { Thumb } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 3); + if (oper[1]^.typ=top_reg) then + bytes:=bytes or ((getsupreg(oper[1]^.reg) and $7) shl 6) + else + bytes:=bytes or ((oper[1]^.val and $1F) shl 6); + end + else if ops=3 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); + if (oper[2]^.typ=top_reg) then + bytes:=bytes or ((getsupreg(oper[2]^.reg) and $7) shl 6) + else + bytes:=bytes or ((oper[2]^.val and $1F) shl 6); + end + else if ops=1 then + begin + if oper[0]^.typ=top_const then + bytes:=bytes or (oper[0]^.val and $FF); + end; + end; + #$61: { Thumb } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or ((getsupreg(oper[0]^.reg) and $8) shr 3) shl 7; - case 0x17: // LDR Rd, expression - ++codes; + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); + end + else if ops=1 then + begin + if oper[0]^.typ=top_const then + bytes:=bytes or (oper[0]^.val and $FF); + end; + end; + #$62..#$63: { Thumb branches } + begin + bytelen:=2; + bytes:=0; - bytes[0] = c | *codes++; + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); - bytes[1] = *codes++; + if insentry^.code[0]=#$63 then + bytes:=bytes or (CondVal[condition] shl 8); - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - if (has_T_code) - { - errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode"); - } - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed"); - } + if oper[0]^.typ=top_const then + begin + if insentry^.code[0]=#$63 then + bytes:=bytes or (((oper[0]^.val shr 1)-1) and $FF) + else + bytes:=bytes or (((oper[0]^.val shr 1)-1) and $3FF); + end + else if oper[0]^.typ=top_reg then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 3); + end + else if oper[0]^.typ=top_ref then + begin + offset:=0; + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[0]^.ref^.offset; + + if insentry^.code[0]=#$63 then + bytes:=bytes or (((offset+4) shr 1) and $FF) + else + bytes:=bytes or (((offset+4) shr 1) and $7FF); + end + end; + #$64: { Thumb: Special encodings } + begin + bytelen:=2; + bytes:=0; - // Rn - implicit R15 - bytes[1] |= 0xF; + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); - if (ins->oprs[1].segment != segment) - { - errfunc (ERR_NONFATAL, "label not in same segment"); - } - data = ins->oprs[1].offset - (offset + 8); + case opcode of + A_SUB: + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + if (ops=3) and + (oper[2]^.typ=top_const) then + bytes:=bytes or ((oper[2]^.val shr 2) and $7F) + else if (ops=2) and + (oper[1]^.typ=top_const) then + bytes:=bytes or ((oper[1]^.val shr 2) and $7F); + end; + A_MUL: + if (ops in [2,3]) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); + end; + A_ADD: + begin + if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl $3); + end + else if (oper[0]^.reg<>NR_STACK_POINTER_REG) and + (oper[2]^.typ=top_const) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7) shl 8; + bytes:=bytes or ((oper[2]^.val shr 2) and $7F); + end + else if (oper[0]^.reg<>NR_STACK_POINTER_REG) and + (oper[2]^.typ=top_reg) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or ((getsupreg(oper[0]^.reg) and $8) shr 3) shl 7; + end + else + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or ((oper[2]^.val shr 2) and $7F); + end; + end; + end; + end; + #$65: { Thumb load/store } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 3); + bytes:=bytes or (getsupreg(oper[1]^.ref^.index) shl 6); + end; + #$66: { Thumb load/store } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.ref^.base) shl 3); + bytes:=bytes or (((oper[1]^.ref^.offset shr ord(insentry^.code[3])) and $1F) shl 6); + end; + #$67: { Thumb load/store } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + if oper[1]^.typ=top_ref then + bytes:=bytes or ((oper[1]^.ref^.offset shr ord(insentry^.code[3])) and $FF) + else + bytes:=bytes or ((oper[1]^.val shr ord(insentry^.code[3])) and $FF); + end; + #$68: { Thumb CB[N]Z } + begin + bytelen:=2; + bytes:=0; - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + { set opers } + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } + if oper[1]^.typ=top_ref then + begin + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[1]^.ref^.offset; + + offset:=offset div 2; + end + else + offset:=oper[1]^.val div 2; - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - break; + bytes:=bytes or ((offset) and $1F) shl 3; + bytes:=bytes or ((offset shr 5) and 1) shl 9; + end; + #$69: { Thumb: Push/Pop/Stm/Ldm } + begin + bytelen:=2; + bytes:=0; - case 0x18: // LDR Rd, [Rn] - ++codes; + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); - bytes[0] = c | *codes++; + case opcode of + A_PUSH: + begin + for r:=0 to 7 do + if r in oper[0]^.regset^ then + bytes:=bytes or (1 shl r); + if RS_R14 in oper[0]^.regset^ then + bytes:=bytes or (1 shl 8); + end; + A_POP: + begin + for r:=0 to 7 do + if r in oper[0]^.regset^ then + bytes:=bytes or (1 shl r); + if RS_R15 in oper[0]^.regset^ then + bytes:=bytes or (1 shl 8); + end; + A_STM: + begin + for r:=0 to 7 do + if r in oper[1]^.regset^ then + bytes:=bytes or (1 shl r); - bytes[1] = *codes++; + if oper[0]^.typ=top_ref then + bytes:=bytes or (getsupreg(oper[0]^.ref^.base) shl 8) + else + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + end; + A_LDM: + begin + for r:=0 to 7 do + if r in oper[1]^.regset^ then + bytes:=bytes or (1 shl r); - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - if (has_T_code) - { - bytes[1] |= 0x20; // write-back - } - else - { - bytes[0] |= 0x01; // implicit pre-index mode - } + if oper[0]^.typ=top_ref then + bytes:=bytes or (getsupreg(oper[0]^.ref^.base) shl 8) + else + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + end; + end; + end; + #$6A: { Thumb: IT } + begin + bytelen:=2; + bytes:=0; - if (has_W_code) - { - bytes[1] |= 0x20; // write-back - } + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or (ord(insentry^.code[2]) shl 0); - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; + bytes:=bytes or (CondVal[oper[0]^.cc] shl 4); - if (c == 0x15) // R15 - data = -8; - else - data = 0; + i_field:=(bytes shr 4) and 1; + i_field:=(i_field shl 1) or i_field; + i_field:=(i_field shl 2) or i_field; - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + bytes:=bytes or ((i_field and ord(insentry^.code[3])) xor (ord(insentry^.code[3]) shr 4)); + end; + #$6B: { Thumb: Data processing (misc) } + begin + bytelen:=2; + bytes:=0; + + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); + { set regs } + if ops>=2 then + begin + if oper[1]^.typ=top_const then + begin + bytes:=bytes or ((getsupreg(oper[0]^.reg) and $7) shl 8); + bytes:=bytes or (oper[1]^.val and $FF); + end + else if oper[1]^.typ=top_reg then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) and $7); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 3); + end; + end + else if ops=1 then + begin + if oper[0]^.typ=top_const then + bytes:=bytes or (oper[0]^.val and $FF); + end; + end; + #$6C: { Thumb: CPS } + begin + bytelen:=2; + bytes:=0; - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - break; - - case 0x19: // LDR Rd, [Rn,#expression] - case 0x20: // LDR Rd, [Rn,Rm] - case 0x21: // LDR Rd, [Rn,Rm,shift] - ++codes; - - bytes[0] = c | *codes++; - - bytes[1] = *codes++; - - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; - if (has_B_code) - bytes[1] |= 0x40; - - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; - - if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <-- - { - bytes[0] |= 0x01; // pre-index mode - if (has_W_code) - { - bytes[1] |= 0x20; - } - if (has_T_code) - { - errfunc (ERR_NONFATAL, "'T' not allowed in pre-index mode"); - } - } - else - { - if (has_T_code) // Forced write-back in post-index mode - { - bytes[1] |= 0x20; - } - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode"); - } - } + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 8); + bytes:=bytes or ord(insentry^.code[2]); - if (keep == 0x19) - { - data = ins->oprs[2].offset; + if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 2); + if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 1); + if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 0); + end; + #$80: { Thumb-2: Dataprocessing } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + if ops=1 then + begin + if oper[0]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16) + else if oper[0]^.typ=top_const then + bytes:=bytes or (oper[0]^.val and $F); + end + else if (ops=2) and + (opcode in [A_CMP,A_CMN,A_TEQ,A_TST]) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + + if oper[1]^.typ=top_const then + encodethumbimm(oper[1]^.val) + else if oper[1]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + end + else if (ops=3) and + (opcode in [A_CMP,A_CMN,A_TEQ,A_TST]) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + + if oper[2]^.typ=top_shifterop then + setthumbshift(2) + else if oper[2]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 12); + end + else if (ops=2) and + (opcode in [A_REV,A_RBIT,A_REV16,A_REVSH,A_CLZ]) then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + end + else if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + + if oper[1]^.typ=top_const then + encodethumbimm(oper[1]^.val) + else if oper[1]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + end + else if ops=3 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + + if oper[2]^.typ=top_const then + encodethumbimm(oper[2]^.val) + else if oper[2]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); + end + else if ops=4 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); + + if oper[3]^.typ=top_shifterop then + setthumbshift(3) + else if oper[3]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[3]^.reg) shl 12); + end; - if (data >= 0x1000) - { - errfunc (ERR_NONFATAL, "too long offset"); - } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20) + else if oppostfix=PF_X then + bytes:=bytes or (1 shl 4) + else if oppostfix=PF_R then + bytes:=bytes or (1 shl 4); + end; + #$81: { Thumb-2: Dataprocessing misc } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - bytes[2] |= ((data & 0xF00) >> 8); - bytes[3] = data & 0xFF; - } - else - { - if (ins->oprs[2].minus == 0) - { - bytes[1] |= 0x80; - } - c = regval (&ins->oprs[2],1); - bytes[3] = c; - - if (keep == 0x21) - { - c = ins->oprs[3].offset; - if (c > 0x1F) - { - errfunc (ERR_NONFATAL, "too large shiftvalue"); - c = c & 0x1F; - } - - bytes[2] |= c >> 1; - if (c & 0x01) - { - bytes[3] |= 0x80; - } - bytes[3] |= shiftval (&ins->oprs[3]) << 5; - } - } + if ops=3 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); - break; + if oper[2]^.typ=top_const then + begin + bytes:=bytes or (oper[2]^.val and $FF); + bytes:=bytes or ((oper[2]^.val and $700) shr 8) shl 12; + bytes:=bytes or ((oper[2]^.val and $800) shr 11) shl 26; + end; + end + else if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); - case 0x22: // LDRH Rd, expression - ++codes; + offset:=0; + if oper[1]^.typ=top_const then + begin + offset:=oper[1]^.val; + end + else if oper[1]^.typ=top_ref then + begin + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[1]^.ref^.offset; - bytes[0] = c | 0x01; // Implicit pre-index + offset:=offset; + end; - bytes[1] = *codes++; + bytes:=bytes or (offset and $FF); + bytes:=bytes or ((offset and $700) shr 8) shl 12; + bytes:=bytes or ((offset and $800) shr 11) shl 26; + bytes:=bytes or ((offset and $F000) shr 12) shl 16; + end; - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$82: { Thumb-2: Shifts } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - // Rn - implicit R15 - bytes[1] |= 0xF; + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + if oper[1]^.typ=top_reg then + begin + offset:=2; + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + end + else + begin + offset:=1; + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 0); + end; - if (ins->oprs[1].segment != segment) - { - errfunc (ERR_NONFATAL, "label not in same segment"); - } + if oper[offset]^.typ=top_const then + begin + bytes:=bytes or (oper[offset]^.val and $3) shl 6; + bytes:=bytes or (oper[offset]^.val and $1C) shl 10; + end + else if oper[offset]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[offset]^.reg) shl 16); - data = ins->oprs[1].offset - (offset + 8); + if (ops>=(offset+2)) and + (oper[offset+1]^.typ=top_const) then + bytes:=bytes or (oper[offset+1]^.val and $1F); - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$84: { Thumb-2: Shifts(width-1) } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - bytes[3] = *codes++; + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + if oper[1]^.typ=top_reg then + begin + offset:=2; + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + end + else + offset:=1; - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - break; + if oper[offset]^.typ=top_const then + begin + bytes:=bytes or (oper[offset]^.val and $3) shl 6; + bytes:=bytes or (oper[offset]^.val and $1C) shl 10; + end; - case 0x23: // LDRH Rd, Rn - ++codes; + if (ops>=(offset+2)) and + (oper[offset+1]^.typ=top_const) then + begin + if opcode in [A_BFI,A_BFC] then + i_field:=oper[offset+1]^.val+oper[offset]^.val-1 + else + i_field:=oper[offset+1]^.val-1; - bytes[0] = c | 0x01; // Implicit pre-index + bytes:=bytes or (i_field and $1F); + end; - bytes[1] = *codes++; + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20); + end; + #$83: { Thumb-2: Saturation } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (oper[1]^.val and $1F); + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 16); - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; + if ops=4 then + setthumbshift(3,true); + end; + #$85: { Thumb-2: Long multiplications } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (c == 0x15) // R15 - data = -8; - else - data = 0; + if ops=4 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[3]^.reg) shl 0); + end; - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + if oppostfix=PF_S then + bytes:=bytes or (1 shl 20) + else if oppostfix=PF_X then + bytes:=bytes or (1 shl 4); + end; + #$86: { Thumb-2: Extension ops } + begin + bytes:=0; + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } - bytes[3] = *codes++; + if ops=2 then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + end + else if ops=3 then + begin + if oper[2]^.typ=top_shifterop then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); + bytes:=bytes or ((oper[2]^.shifterop^.shiftimm shr 3) shl 4); + end + else + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); + end; + end + else if ops=4 then + begin + if oper[3]^.typ=top_shifterop then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[2]^.reg) shl 0); + bytes:=bytes or ((oper[3]^.shifterop^.shiftimm shr 3) shl 4); + end; + end; + end; + #$87: { Thumb-2: PLD/PLI } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; + if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=offset+oper[0]^.ref^.offset; + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or (offset and $FFF); + end + else + begin + bytes:=bytes or ($3 shl 10); - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - break; + offset:=-offset; + bytes:=bytes or (offset and $FF); + end; + end + else + begin + bytes:=bytes or getsupreg(oper[0]^.ref^.index); + { set shift } + with oper[0]^.ref^ do + if shiftmode=SM_LSL then + bytes:=bytes or ((shiftimm and $1F) shl 4); + end; + end; + #$88: { Thumb-2: LDR/STR } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or (ord(insentry^.code[4]) shl 0); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=(offset+oper[1]^.ref^.offset) shr ord(insentry^.code[5]); + if offset>=0 then + begin + if not (opcode in [A_LDRT,A_LDRSBT,A_LDRSHT,A_LDRBT,A_LDRHT]) then + bytes:=bytes or (1 shl 23); + { set U flag } + if (oper[1]^.ref^.addressmode<>AM_OFFSET) then + bytes:=bytes or (1 shl 9); + bytes:=bytes or offset + end + else + begin + bytes:=bytes or (1 shl 11); - case 0x24: // LDRH Rd, Rn, expression - case 0x25: // LDRH Rd, Rn, Rm - ++codes; + offset:=-offset; + bytes:=bytes or offset + end; + end + else + begin + { set I flag } + bytes:=bytes or (1 shl 25); + bytes:=bytes or getsupreg(oper[1]^.ref^.index); + { set shift } + with oper[1]^.ref^ do + if shiftmode<>SM_None then + bytes:=bytes or ((shiftimm and $1F) shl 4); + end; - bytes[0] = c; + if not (opcode in [A_LDRT,A_LDRSBT,A_LDRSHT,A_LDRBT,A_LDRHT]) then + begin + { set W bit } + if oper[1]^.ref^.addressmode<>AM_OFFSET then + bytes:=bytes or (1 shl 8); + { set P bit if necessary } + if oper[1]^.ref^.addressmode<>AM_POSTINDEXED then + bytes:=bytes or (1 shl 10); + end; + end; + #$89: { Thumb-2: LDRD/STRD } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or (ord(insentry^.code[4]) shl 0); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[1]^.reg) shl 8; + bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; + if getregtype(oper[2]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[2]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=(offset+oper[2]^.ref^.offset) div 4; + if offset>=0 then + begin + { set U flag } + bytes:=bytes or (1 shl 23); + bytes:=bytes or offset + end + else + begin + offset:=-offset; + bytes:=bytes or offset + end; + end + else + begin + message(asmw_e_invalid_opcode_and_operands); + end; + { set W bit } + if oper[2]^.ref^.addressmode<>AM_OFFSET then + bytes:=bytes or (1 shl 21); + { set P bit if necessary } + if oper[2]^.ref^.addressmode<>AM_POSTINDEXED then + bytes:=bytes or (1 shl 24); + end; + #$8A: { Thumb-2: LDREX } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or (ord(insentry^.code[4]) shl 0); + { set Rn and Rd } + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + + if (ops=2) and (opcode in [A_LDREX]) then + begin + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + if getregtype(oper[1]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[1]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=(offset+oper[1]^.ref^.offset) div 4; + if offset>=0 then + begin + bytes:=bytes or offset + end + else + begin + message(asmw_e_invalid_opcode_and_operands); + end; + end + else + begin + message(asmw_e_invalid_opcode_and_operands); + end; + end + else if (ops=2) then + begin + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + end + else + begin + bytes:=bytes or getsupreg(oper[1]^.reg) shl 8; + bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; + end; + end; + #$8B: { Thumb-2: STREX } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or (ord(insentry^.code[4]) shl 0); + { set Rn and Rd } + if (ops=3) and (opcode in [A_STREX]) then + begin + bytes:=bytes or getsupreg(oper[0]^.reg) shl 8; + bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; + if getregtype(oper[2]^.ref^.index)=R_INVALIDREGISTER then + begin + { set offset } + offset:=0; + currsym:=objdata.symbolref(oper[2]^.ref^.symbol); + if assigned(currsym) then + offset:=currsym.offset-insoffset-8; + offset:=(offset+oper[2]^.ref^.offset) div 4; + if offset>=0 then + begin + bytes:=bytes or offset + end + else + begin + message(asmw_e_invalid_opcode_and_operands); + end; + end + else + begin + message(asmw_e_invalid_opcode_and_operands); + end; + end + else if (ops=3) then + begin + bytes:=bytes or getsupreg(oper[0]^.reg) shl 0; + bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; + end + else + begin + bytes:=bytes or getsupreg(oper[0]^.reg) shl 0; + bytes:=bytes or getsupreg(oper[1]^.reg) shl 12; + bytes:=bytes or getsupreg(oper[2]^.reg) shl 8; + bytes:=bytes or getsupreg(oper[3]^.ref^.base) shl 16; + end; + end; + #$8C: { Thumb-2: LDM/STM } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or (ord(insentry^.code[4]) shl 0); - bytes[1] = *codes++; + if oper[0]^.typ=top_reg then + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16) + else + begin + bytes:=bytes or (getsupreg(oper[0]^.ref^.base) shl 16); + if oper[0]^.ref^.addressmode<>AM_OFFSET then + bytes:=bytes or (1 shl 21); + end; - // Rd - bytes[2] = regval (&ins->oprs[0],1) << 4; + for r:=0 to 15 do + if r in oper[1]^.regset^ then + bytes:=bytes or (1 shl r); - // Rn - c = regval (&ins->oprs[1],1); - bytes[1] |= c; + case oppostfix of + PF_None,PF_IA,PF_FD: bytes:=bytes or ($1 shl 23); + PF_DB,PF_EA: bytes:=bytes or ($2 shl 23); + end; + end; + #$8D: { Thumb-2: BL/BLX } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 8); + { set offset } + if oper[0]^.typ=top_const then + offset:=(oper[0]^.val shr 1) and $FFFFFF + else + begin + currsym:=objdata.symbolref(oper[0]^.ref^.symbol); + if (currsym.bind<>AB_LOCAL) and (currsym.objsection<>objdata.CurrObjSec) then + begin + objdata.writereloc(oper[0]^.ref^.offset,0,currsym,RELOC_RELATIVE_24_THUMB); + offset:=$FFFFFE + end + else + offset:=((currsym.offset-insoffset-8) shr 1) and $FFFFFF; + end; - if (ins->oprs[ins->operands-1].bracket) // FIXME: Bracket on last operand -> pre-index <-- - { - bytes[0] |= 0x01; // pre-index mode - if (has_W_code) - { - bytes[1] |= 0x20; - } - } - else - { - if (has_W_code) - { - errfunc (ERR_NONFATAL, "'!' not allowed in post-index mode"); - } - } + bytes:=bytes or ((offset shr 00) and $7FF) shl 0; + bytes:=bytes or ((offset shr 11) and $3FF) shl 16; + bytes:=bytes or (((offset shr 21) xor (offset shr 23) xor 1) and $1) shl 11; + bytes:=bytes or (((offset shr 22) xor (offset shr 23) xor 1) and $1) shl 13; + bytes:=bytes or ((offset shr 23) and $1) shl 26; + end; + #$8E: { Thumb-2: TBB/TBH } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); + { set Rn and Rm } + bytes:=bytes or getsupreg(oper[0]^.ref^.base) shl 16; + + if getregtype(oper[0]^.ref^.index)=R_INVALIDREGISTER then + message(asmw_e_invalid_effective_address) + else + begin + bytes:=bytes or getsupreg(oper[0]^.ref^.index); - bytes[3] = *codes++; + if (opcode=A_TBH) and + (oper[0]^.ref^.shiftmode<>SM_LSL) and + (oper[0]^.ref^.shiftimm<>1) then + message(asmw_e_invalid_effective_address); + end; + end; + #$8F: { Thumb-2: CPSxx } + begin + { set opcode } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (keep == 0x24) - { - data = ins->oprs[2].offset; + if (oper[0]^.typ=top_modeflags) then + begin + if mfA in oper[0]^.modeflags then bytes:=bytes or (1 shl 7); + if mfI in oper[0]^.modeflags then bytes:=bytes or (1 shl 6); + if mfF in oper[0]^.modeflags then bytes:=bytes or (1 shl 5); + end; - if (data < 0) - { - data = -data; - } - else - { - bytes[1] |= 0x80; - } + if (ops=2) then + bytes:=bytes or (oper[1]^.val and $1F) + else if (ops=1) and + (oper[0]^.typ=top_const) then + bytes:=bytes or (oper[0]^.val and $1F); + end; + #$96: { Thumb-2: MSR/MRS } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - if (data >= 0x100) - { - errfunc (ERR_NONFATAL, "too long offset"); - } + if opcode=A_MRS then + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8); - bytes[2] |= ((data & 0xF0) >> 4); - bytes[3] |= data & 0xF; - } - else - { - if (ins->oprs[2].minus == 0) - { - bytes[1] |= 0x80; - } - c = regval (&ins->oprs[2],1); - bytes[3] |= c; + case oper[1]^.reg of + NR_MSP: bytes:=bytes or $08; + NR_PSP: bytes:=bytes or $09; - } - break; + NR_IPSR: bytes:=bytes or $05; + NR_EPSR: bytes:=bytes or $06; + NR_APSR: bytes:=bytes or $00; - case 0x26: // LDM/STM Rn, {reg-list} - ++codes; + NR_PRIMASK: bytes:=bytes or $10; + NR_BASEPRI: bytes:=bytes or $11; + NR_BASEPRI_MAX: bytes:=bytes or $12; + NR_FAULTMASK: bytes:=bytes or $13; + NR_CONTROL: bytes:=bytes or $14; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end + else + begin + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 16); - bytes[0] = c; + case oper[0]^.reg of + NR_APSR, + NR_APSR_nzcvqg: bytes:=bytes or $C00; + NR_APSR_g: bytes:=bytes or $400; + NR_APSR_nzcvq: bytes:=bytes or $800; - bytes[0] |= ( *codes >> 4) & 0xF; - bytes[1] = ( *codes << 4) & 0xF0; - ++codes; + NR_MSP: bytes:=bytes or $08; + NR_PSP: bytes:=bytes or $09; - if (has_W_code) - { - bytes[1] |= 0x20; - } - if (has_F_code) - { - bytes[1] |= 0x40; - } + NR_PRIMASK: bytes:=bytes or $10; + NR_BASEPRI: bytes:=bytes or $11; + NR_BASEPRI_MAX: bytes:=bytes or $12; - // Rn - bytes[1] |= regval (&ins->oprs[0],1); + NR_FAULTMASK: bytes:=bytes or $13; + NR_CONTROL: bytes:=bytes or $14; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end; + end; + #$A0: { FPA: CPDT(LDF/STF) } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or (ord(insentry^.code[3]) shl 8); + bytes:=bytes or ord(insentry^.code[4]); - data = ins->oprs[1].basereg; + if ops=2 then + begin + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + + bytes:=bytes or getsupreg(oper[1]^.ref^.base) shl 16; + bytes:=bytes or ((oper[1]^.ref^.offset shr 2) and $FF); + if oper[1]^.ref^.offset>=0 then + bytes:=bytes or (1 shl 23); + + if oper[1]^.ref^.addressmode<>AM_OFFSET then + bytes:=bytes or (1 shl 21); + if oper[1]^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 24); + + case oppostfix of + PF_D: bytes:=bytes or (0 shl 22) or (1 shl 15); + PF_E: bytes:=bytes or (1 shl 22) or (0 shl 15); + PF_P: bytes:=bytes or (1 shl 22) or (1 shl 15); + end; + end + else + begin + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; - bytes[2] = ((data >> 8) & 0xFF); - bytes[3] = (data & 0xFF); + case oper[1]^.val of + 1: bytes:=bytes or (1 shl 15); + 2: bytes:=bytes or (1 shl 22); + 3: bytes:=bytes or (1 shl 22) or (1 shl 15); + 4: ; + else + message1(asmw_e_invalid_opcode_and_operands, 'Invalid count for LFM/SFM'); + end; - break; + bytes:=bytes or getsupreg(oper[2]^.ref^.base) shl 16; + bytes:=bytes or ((oper[2]^.ref^.offset shr 2) and $FF); + if oper[2]^.ref^.offset>=0 then + bytes:=bytes or (1 shl 23); - case 0x27: // SWP Rd, Rm, [Rn] - ++codes; + if oper[2]^.ref^.addressmode<>AM_OFFSET then + bytes:=bytes or (1 shl 21); + if oper[2]^.ref^.addressmode=AM_PREINDEXED then + bytes:=bytes or (1 shl 24); + end; + end; + #$A1: { FPA: CPDO } + begin + { set instruction code } + bytes:=bytes or ($E shl 24); + bytes:=bytes or (ord(insentry^.code[1]) shl 15); + bytes:=bytes or ((ord(insentry^.code[2]) shr 1) shl 20); + bytes:=bytes or (1 shl 8); - bytes[0] = c; + bytes:=bytes or getsupreg(oper[0]^.reg) shl 12; + if ops=2 then + begin + if oper[1]^.typ=top_reg then + bytes:=bytes or getsupreg(oper[1]^.reg) shl 0 + else + case oper[1]^.val of + 0: bytes:=bytes or $8; + 1: bytes:=bytes or $9; + 2: bytes:=bytes or $A; + 3: bytes:=bytes or $B; + 4: bytes:=bytes or $C; + 5: bytes:=bytes or $D; + //0.5: bytes:=bytes or $E; + 10: bytes:=bytes or $F; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end + else + begin + bytes:=bytes or getsupreg(oper[1]^.reg) shl 16; + if oper[2]^.typ=top_reg then + bytes:=bytes or getsupreg(oper[2]^.reg) shl 0 + else + case oper[2]^.val of + 0: bytes:=bytes or $8; + 1: bytes:=bytes or $9; + 2: bytes:=bytes or $A; + 3: bytes:=bytes or $B; + 4: bytes:=bytes or $C; + 5: bytes:=bytes or $D; + //0.5: bytes:=bytes or $E; + 10: bytes:=bytes or $F; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end; - bytes[0] |= *codes++; + case roundingmode of + RM_P: bytes:=bytes or (1 shl 5); + RM_M: bytes:=bytes or (2 shl 5); + RM_Z: bytes:=bytes or (3 shl 5); + end; - bytes[1] = regval (&ins->oprs[2],1); - if (has_B_code) - { - bytes[1] |= 0x40; - } - bytes[2] = regval (&ins->oprs[0],1) << 4; - bytes[3] = *codes++; - bytes[3] |= regval (&ins->oprs[1],1); - break; + case oppostfix of + PF_S: bytes:=bytes or (0 shl 19) or (0 shl 7); + PF_D: bytes:=bytes or (0 shl 19) or (1 shl 7); + PF_E: bytes:=bytes or (1 shl 19) or (0 shl 7); + else + message1(asmw_e_invalid_opcode_and_operands, 'Precision cannot be undefined'); + end; + end; + #$A2: { FPA: CPDO } + begin + { set instruction code } + bytes:=bytes or (ord(insentry^.code[1]) shl 24); + bytes:=bytes or (ord(insentry^.code[2]) shl 16); + bytes:=bytes or ($11 shl 4); - default: - errfunc (ERR_FATAL, "unknown decoding of instruction"); + case opcode of + A_FLT: + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 12); - bytes[0] = c; - // And a fix nibble - ++codes; - bytes[0] |= *codes++; + case roundingmode of + RM_P: bytes:=bytes or (1 shl 5); + RM_M: bytes:=bytes or (2 shl 5); + RM_Z: bytes:=bytes or (3 shl 5); + end; - if ( *codes == 0x01) // An I bit - { + case oppostfix of + PF_S: bytes:=bytes or (0 shl 19) or (0 shl 7); + PF_D: bytes:=bytes or (0 shl 19) or (1 shl 7); + PF_E: bytes:=bytes or (1 shl 19) or (0 shl 7); + else + message1(asmw_e_invalid_opcode_and_operands, 'Precision cannot be undefined'); + end; + end; + A_FIX: + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + bytes:=bytes or (getsupreg(oper[1]^.reg) shl 0); - } - if ( *codes == 0x02) // An I bit - { + case roundingmode of + RM_P: bytes:=bytes or (1 shl 5); + RM_M: bytes:=bytes or (2 shl 5); + RM_Z: bytes:=bytes or (3 shl 5); + end; + end; + A_WFS,A_RFS,A_WFC,A_RFC: + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 12); + end; + A_CMF,A_CNF,A_CMFE,A_CNFE: + begin + bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16); - } - ++codes; - } - out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG); -} + if oper[1]^.typ=top_reg then + bytes:=bytes or getsupreg(oper[1]^.reg) shl 0 + else + case oper[1]^.val of + 0: bytes:=bytes or $8; + 1: bytes:=bytes or $9; + 2: bytes:=bytes or $A; + 3: bytes:=bytes or $B; + 4: bytes:=bytes or $C; + 5: bytes:=bytes or $D; + //0.5: bytes:=bytes or $E; + 10: bytes:=bytes or $F; + else + Message(asmw_e_invalid_opcode_and_operands); + end; + end; + end; + end; + #$fe: // No written data + begin + exit; + end; + #$ff: + internalerror(2005091101); + else + begin + writeln(ord(insentry^.code[0]), ' - ', opcode); + internalerror(2005091102); + end; + end; -*) -{$endif dummy} + { Todo: Decide whether the code above should take care of writing data in an order that makes senes } + if (insentry^.code[0] in [#$80..#$96]) and (bytelen=4) then + bytes:=((bytes shr 16) and $FFFF) or ((bytes and $FFFF) shl 16); - constructor tai_thumb_func.create; - begin - inherited create; - typ:=ait_thumb_func; - end; + { we're finished, write code } + objdata.writebytes(bytes,bytelen); + end; begin cai_align:=tai_align; diff --git a/fpcsrc/compiler/arm/agarmgas.pas b/fpcsrc/compiler/arm/agarmgas.pas index 68fd5680..07e9068e 100644 --- a/fpcsrc/compiler/arm/agarmgas.pas +++ b/fpcsrc/compiler/arm/agarmgas.pas @@ -42,11 +42,14 @@ unit agarmgas; end; TArmInstrWriter=class(TCPUInstrWriter) + unified_syntax: boolean; + procedure WriteInstruction(hp : tai);override; end; TArmAppleGNUAssembler=class(TAppleGNUassembler) constructor create(smart: boolean); override; + procedure WriteExtraHeader; override; end; @@ -93,6 +96,8 @@ unit agarmgas; begin inherited create(smart); InstrWriter := TArmInstrWriter.create(self); + if GenerateThumb2Code then + TArmInstrWriter(InstrWriter).unified_syntax:=true; end; @@ -109,6 +114,8 @@ unit agarmgas; result:='-mfpu=vfpv3-d16 '+result; if (current_settings.fputype = fpu_fpv4_s16) then result:='-mfpu=fpv4-sp-d16 '+result; + if (current_settings.fputype = fpu_vfpv4) then + result:='-mfpu=vfpv4 '+result; if GenerateThumb2Code then result:='-march='+cputype_to_gas_march[current_settings.cputype]+' -mthumb -mthumb-interwork '+result @@ -126,7 +133,7 @@ unit agarmgas; procedure TArmGNUAssembler.WriteExtraHeader; begin inherited WriteExtraHeader; - if GenerateThumb2Code then + if TArmInstrWriter(InstrWriter).unified_syntax then AsmWriteLn(#9'.syntax unified'); end; @@ -138,6 +145,15 @@ unit agarmgas; begin inherited create(smart); InstrWriter := TArmInstrWriter.create(self); + TArmInstrWriter(InstrWriter).unified_syntax:=true; + end; + + + procedure TArmAppleGNUAssembler.WriteExtraHeader; + begin + inherited WriteExtraHeader; + if TArmInstrWriter(InstrWriter).unified_syntax then + AsmWriteLn(#9'.syntax unified'); end; @@ -208,7 +224,7 @@ unit agarmgas; var hs : string; first : boolean; - r : tsuperregister; + r, rs : tsuperregister; begin case o.typ of top_reg: @@ -230,14 +246,44 @@ unit agarmgas; begin getopstr:='{'; first:=true; - for r:=RS_R0 to RS_R15 do - if r in o.regset^ then - begin - if not(first) then - getopstr:=getopstr+','; - getopstr:=getopstr+gas_regname(newreg(o.regtyp,r,o.subreg)); - first:=false; - end; + if R_SUBFS=o.subreg then + begin + for r:=0 to 31 do // S0 to S31 + if r in o.regset^ then + begin + if not(first) then + getopstr:=getopstr+','; + if odd(r) then + rs:=(r shr 1)+RS_S1 + else + rs:=(r shr 1)+RS_S0; + getopstr:=getopstr+gas_regname(newreg(o.regtyp,rs,o.subreg)); + first:=false; + end; + end + else if R_SUBFD=o.subreg then + begin + for r:=0 to 31 do + if r in o.regset^ then + begin + if not(first) then + getopstr:=getopstr+','; + rs:=r+RS_D0; + getopstr:=getopstr+gas_regname(newreg(o.regtyp,rs,o.subreg)); + first:=false; + end; + end + else + begin + for r:=RS_R0 to RS_R15 do + if r in o.regset^ then + begin + if not(first) then + getopstr:=getopstr+','; + getopstr:=getopstr+gas_regname(newreg(o.regtyp,r,o.subreg)); + first:=false; + end; + end; getopstr:=getopstr+'}'; if o.usermode then getopstr:=getopstr+'^'; @@ -289,15 +335,17 @@ unit agarmgas; sep: string[3]; begin op:=taicpu(hp).opcode; + postfix:=''; if GenerateThumb2Code then begin - postfix:=''; if taicpu(hp).wideformat then postfix:='.w'; - + end; + if unified_syntax then + begin if taicpu(hp).ops = 0 then s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix] - else if (taicpu(hp).opcode>=A_VABS) and (taicpu(hp).opcode<=A_VSUB) then + else if taicpu(hp).oppostfix in [PF_8..PF_U32F64] then s:=#9+gas_op2str[op]+cond2str[taicpu(hp).condition]+oppostfix2str[taicpu(hp).oppostfix] else s:=#9+gas_op2str[op]+oppostfix2str[taicpu(hp).oppostfix]+cond2str[taicpu(hp).condition]+postfix; // Conditional infixes are deprecated in unified syntax @@ -314,7 +362,7 @@ unit agarmgas; // writeln(taicpu(hp).fileinfo.line); { LDM and STM use references as first operand but they are written like a register } - if (i=0) and (op in [A_LDM,A_STM,A_FSTM,A_FLDM]) then + if (i=0) and (op in [A_LDM,A_STM,A_FSTM,A_FLDM,A_VSTM,A_VLDM]) then begin case taicpu(hp).oper[0]^.typ of top_ref: diff --git a/fpcsrc/compiler/arm/aoptcpu.pas b/fpcsrc/compiler/arm/aoptcpu.pas index bd786016..e015ee9b 100644 --- a/fpcsrc/compiler/arm/aoptcpu.pas +++ b/fpcsrc/compiler/arm/aoptcpu.pas @@ -2353,7 +2353,7 @@ Implementation { set of opcode which might or do write to memory } { TODO : extend armins.dat to contain r/w info } opcode_could_mem_write = [A_B,A_BL,A_BLX,A_BKPT,A_BX,A_STR,A_STRB,A_STRBT, - A_STRH,A_STRT,A_STF,A_SFM,A_STM,A_FSTS,A_FSTD]; + A_STRH,A_STRT,A_STF,A_SFM,A_STM,A_FSTS,A_FSTD,A_VSTR,A_VSTM]; { adjust the register live information when swapping the two instructions p and hp1, diff --git a/fpcsrc/compiler/arm/armatt.inc b/fpcsrc/compiler/arm/armatt.inc index 602cb025..363944ff 100644 --- a/fpcsrc/compiler/arm/armatt.inc +++ b/fpcsrc/compiler/arm/armatt.inc @@ -1,12 +1,9 @@ { don't edit, this file is generated from armins.dat } ( 'none', -'abs', -'acs', -'asn', -'atn', 'adc', 'add', +'addw', 'adf', 'adr', 'and', @@ -17,24 +14,18 @@ 'bkpt', 'bx', 'cdp', -'cmf', -'cmfe', 'cmn', 'cmp', +'cmf', +'cmfe', +'stf', +'ldf', +'lfm', 'clz', -'cnf', -'cos', 'cps', 'cpsid', 'cpsie', -'dvf', 'eor', -'exp', -'fdv', -'flt', -'fix', -'fml', -'frd', 'ldc', 'ldm', 'ldrbt', @@ -44,41 +35,32 @@ 'ldrsb', 'ldrsh', 'ldrt', -'ldf', -'lfm', -'lgn', -'log', 'mcr', +'mcr2', +'mrc', +'mrc2', +'mcrr', +'mcrr2', +'mrrc', +'mrrc2', 'mla', 'mov', -'mrc', 'mrs', 'msr', -'mnf', -'muf', 'mul', 'mvf', 'mvn', +'vmov', 'nop', +'orn', 'orr', -'rdf', -'rfs', -'rfc', -'rmf', -'rpw', 'rsb', 'rsc', -'rsf', -'rnd', -'pol', 'sbc', 'sfm', 'sin', 'smlal', 'smull', -'sqt', -'suf', -'stf', 'stm', 'str', 'strb', @@ -89,16 +71,14 @@ 'swi', 'swp', 'swpb', -'tan', 'teq', 'tst', 'umlal', 'umull', 'wfs', 'ldrd', -'mcrr', -'mrrc', 'pld', +'pldw', 'qadd', 'qdadd', 'qdsub', @@ -113,6 +93,12 @@ 'smlaltt', 'smlawb', 'smlawt', +'vldm', +'vstm', +'vpop', +'vpush', +'vldr', +'vstr', 'smulbb', 'smulbt', 'smultb', @@ -120,67 +106,13 @@ 'smulwb', 'smulwt', 'strd', -'fabsd', -'fabss', -'faddd', -'fadds', -'fcmpd', -'fcmped', -'fcmpes', -'fcmpezd', -'fcmpezs', -'fcmps', -'fcmpzd', -'fcmpzs', -'fcpyd', -'fcpys', -'fcvtds', -'fcvtsd', -'fdivd', -'fdivs', -'fldd', -'fldm', -'flds', -'fmacd', -'fmacs', -'fmdhr', -'fmdlr', -'fmrdh', -'fmrdl', -'fmrs', -'fmrx', -'fmscd', -'fmscs', -'fmsr', -'fmstat', -'fmuld', -'fmuls', -'fmxr', -'fnegd', -'fnegs', -'fnmacd', -'fnmacs', -'fnmscd', -'fnmscs', -'fnmuld', -'fnmuls', -'fsitod', -'fsitos', -'fsqrtd', -'fsqrts', +'ldrht', +'strht', +'ldrsbt', +'ldrsht', 'fstd', 'fstm', 'fsts', -'fsubd', -'fsubs', -'ftosid', -'ftosis', -'ftouid', -'ftouis', -'fuitod', -'fuitos', -'fmdrr', -'fmrrd', 'bfc', 'bfi', 'clrex', @@ -188,8 +120,13 @@ 'ldrexb', 'ldrexd', 'ldrexh', +'strex', +'strexb', +'strexd', +'strexh', 'mls', -'pkh', +'pkhbt', +'pkhtb', 'pli', 'qadd16', 'qadd8', @@ -212,6 +149,8 @@ 'lsr', 'lsl', 'ror', +'rrx', +'umaal', 'shadd16', 'shadd8', 'shasx', @@ -233,49 +172,102 @@ 'ssax', 'ssub16', 'ssub8', -'strex', -'strexb', -'strexd', -'strexh', 'sxtab', 'sxtab16', 'sxtah', +'ubfx', +'uxtab', +'uxtab16', +'uxtah', 'sxtb', 'sxtb16', +'sxth', 'uxtb', +'uxtb16', 'uxth', -'sxth', 'uadd16', 'uadd8', 'uasx', -'ubfx', 'uhadd16', 'uhadd8', 'uhasx', 'uhsax', 'uhsub16', 'uhsub8', -'umaal', 'uqadd16', 'uqadd8', 'uqasx', 'uqsax', 'uqsub16', 'uqsub8', -'uqsad8', -'uqsada8', +'usad8', +'usada8', 'usat', 'usat16', 'usax', 'usub16', 'usub8', -'uxtab', -'uxtab16', -'uxtah', -'uxtb16', 'wfe', 'wfi', 'yield', +'fabsd', +'fabss', +'faddd', +'fadds', +'fcmpd', +'fcmps', +'fcmped', +'fcmpes', +'fcmpzd', +'fcmpzs', +'fcmpezd', +'fcmpezs', +'fcpyd', +'fcpys', +'fcvtds', +'fcvtsd', +'fdivd', +'fdivs', +'fldd', +'fldm', +'flds', +'fmacd', +'fmacs', +'fmdhr', +'fmdlr', +'fmrdh', +'fmrdl', +'fmrs', +'fmrx', +'fmscd', +'fmscs', +'fmsr', +'fmstat', +'fmuld', +'fmuls', +'fmxr', +'fnegd', +'fnegs', +'fnmacd', +'fnmacs', +'fnmscd', +'fnmscs', +'fnmuld', +'fnmuls', +'fsitod', +'fsitos', +'fsqrtd', +'fsqrts', +'fsubd', +'fsubs', +'ftosid', +'ftosis', +'ftouid', +'ftouis', +'fuitod', +'fuitos', +'fmdrr', +'fmrrd', 'pop', 'push', 'sdiv', @@ -306,29 +298,59 @@ 'vcmp', 'vcmpe', 'vcvt', +'vcvtr', 'vdiv', -'vldm', -'vldr', -'vmov', 'vmrs', 'vmsr', -'vmul', 'vmla', 'vmls', +'vmul', 'vnmla', 'vnmls', +'vnmul', 'vfma', 'vfms', 'vfnma', 'vfnms', 'vneg', -'vnmul', -'vpop', -'vpush', 'vsqrt', -'vstm', -'vstr', 'vsub', +'dmb', +'isb', +'dsb', +'smc', 'neg', -'svc' +'svc', +'bxj', +'udf', +'tan', +'sqt', +'suf', +'rsf', +'rnd', +'pol', +'rdf', +'rfs', +'rfc', +'wfc', +'rmf', +'rpw', +'mnf', +'muf', +'abs', +'acs', +'asn', +'atn', +'cnf', +'cnfe', +'cos', +'dvf', +'exp', +'fdv', +'flt', +'fix', +'fml', +'frd', +'lgn', +'log' ); diff --git a/fpcsrc/compiler/arm/armatts.inc b/fpcsrc/compiler/arm/armatts.inc index 2c9aeac2..fcab30cb 100644 --- a/fpcsrc/compiler/arm/armatts.inc +++ b/fpcsrc/compiler/arm/armatts.inc @@ -330,5 +330,27 @@ attsufNONE, attsufNONE, attsufNONE, attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, +attsufNONE, attsufNONE ); diff --git a/fpcsrc/compiler/arm/armins.dat b/fpcsrc/compiler/arm/armins.dat index 411983bb..edfa65fa 100644 --- a/fpcsrc/compiler/arm/armins.dat +++ b/fpcsrc/compiler/arm/armins.dat @@ -85,713 +85,1756 @@ [NONE] void void none -[ABScc] +[ADCcc] +reglo,reglo \x6B\x41\x40 THUMB,ARMv4T -[ACScc] +reg32,immshifter \x80\xF1\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEB\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF1\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEB\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEB\x40\x0\x0 THUMB32,WIDE,ARMv6T2 -[ASNcc] +reg32,reg32,reg32 \4\x0\xA0 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\xA0 ARM32,ARMv4 +reg32,reg32,immshifter \7\x2\xA0 ARM32,ARMv4 -[ATNcc] +[ADDcc] +reg32,reg32 \x61\x44\x0 THUMB,ARMv4T +reglo,reglo,reglo \x60\x18\x0 THUMB,ARMv4T -[ADCcc] -reg32,reg32,reg32 \4\x0\xA0 ARM7 -reg32,reg32,reg32,reg32 \5\x0\xA0 ARM7 -reg32,reg32,reg32,imm \6\x0\xA0 ARM7 -reg32,reg32,imm \7\x2\xA0 ARM7 +reglo,immshifter \x60\x1C\x0 THUMB,ARMv4T +reglo,reglo,immshifter \x60\x1C\x0 THUMB,ARMv4T +reglo,immshifter \x6B\x30\x0 THUMB,ARMv4T -[ADDcc] -reg32,reg32,reg32 \4\x0\x80 ARM7 -reg32,reg32,reg32,reg32 \5\x0\x80 ARM7 -reg32,reg32,reg32,imm \6\x0\x80 ARM7 -reg32,reg32,imm \7\x2\x80 ARM7 +reglo,regsp,immshifter \x64\xA8\x00 THUMB,ARMv4T +regsp,regsp,immshifter \x64\xB0\x00 THUMB,ARMv4T +reg32,regsp,reg32 \x64\x44\x68 THUMB,ARMv4T +regsp,reg32 \x64\x44\x85 THUMB,ARMv4T + +reg32,immshifter \x80\xF1\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xEB\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF1\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xEB\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEB\x0\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,reg32 \4\x0\x80 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\x80 ARM32,ARMv4 +reg32,reg32,immshifter \7\x2\x80 ARM32,ARMv4 + +[ADDWcc] +reg32,reg32,immshifter \x81\xF2\x0\x0\x0 THUMB32,ARMv6T2 [ADFcc] +fpureg,fpureg,fpureg \xA1\0\x0 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x0 ARM32,FPA [ADRcc] +;reg32,immshifter \x33\x2\x0F ARM32,ARMv4 +;reg32,imm32 \x33\x2\x0F ARM32,ARMv4 +reglo,immshifter \x67\xA0\x0\2 THUMB,ARMv4T +reglo,memam6 \x67\xA0\x0\2 THUMB,ARMv4T + +reg32,imm32 \x81\xF2\xAF\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,immshifter \x81\xF2\xAF\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x81\xF2\xAF\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,memam2 \x33\x2\x0F ARM32,ARMv4 [ANDcc] -reg32,reg32,reg32 \4\x0\x00 ARM7 -reg32,reg32,reg32,reg32 \5\x0\x00 ARM7 -reg32,reg32,reg32,imm \6\x0\x00 ARM7 -reg32,reg32,imm \7\x2\x00 ARM7 +reglo,reglo \x6B\x40\x00 THUMB,ARMv4T + +reg32,immshifter \x80\xF0\x0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF0\x0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEA\x0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\x0\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,reg32 \x4\x0\x00 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \x6\x0\x00 ARM32,ARMv4 +reg32,reg32,immshifter \x7\x2\x00 ARM32,ARMv4 [Bcc] -mem32 \1\x0A ARM7 -imm24 \1\x0A ARM7 +imm24 \x62\xE0\x0 THUMB,ARMv4T +immshifter \x62\xE0\x0 THUMB,ARMv4T +mem32 \x62\xE0\x0 THUMB,ARMv4T + +imm24 \x63\xD0\x0 THUMB,ARMv4T +immshifter \x63\xD0\x0 THUMB,ARMv4T +mem32 \x63\xD0\x0 THUMB,ARMv4T + +imm24 \x1\x0A ARM32,ARMv4 +mem32 \x1\x0A ARM32,ARMv4 [BICcc] -reg32,reg32,reg32 \4\x1\xC0 ARM7 -reg32,reg32,reg32,reg32 \5\x1\xC0 ARM7 -reg32,reg32,reg32,imm \6\x1\xC0 ARM7 -reg32,reg32,imm \7\x3\xC0 ARM7 +reglo,reglo \x6B\x43\x80 THUMB,ARMv4T + +reg32,immshifter \x80\xF0\x20\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x20\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x20\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF0\x20\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEA\x20\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\x20\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,reg32 \x6\x1\xC0 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \x6\x1\xC0 ARM32,ARMv4 +reg32,reg32,immshifter \x7\x3\xC0 ARM32,ARMv4 [BLcc] -mem32 \1\x0B ARM7 -imm24 \1\x0B ARM7 +imm24 \x8D\xF0\xD0 THUMB,THUMB32,ARMv4T +immshifter \x8D\xF0\xD0 THUMB,THUMB32,ARMv4T +mem32 \x8D\xF0\xD0 THUMB,THUMB32,ARMv4T + +imm24 \x1\x0B ARM32,ARMv4 +mem32 \x1\x0B ARM32,ARMv4 [BLX] -mem32 \xff ARM7 -imm24 \xff ARM7 +reg32 \x62\x47\x80 THUMB,ARMv4T + +immshifter \x8D\xF0\xC0 THUMB32,ARMv6T2 +imm24 \x8D\xF0\xC0 THUMB32,ARMv6T2 +mem32 \x8D\xF0\xC0 THUMB32,ARMv6T2 + +imm24 \x28\xFA ARM32,ARMv5T +mem32 \x28\xFA ARM32,ARMv5T +reg32 \3\x01\x2F\xFF\x30 ARM32,ARMv5T [BKPTcc] +immshifter \x60\xBE\x0 THUMB,ARMv5T +imm \x31\x1\x20\x70 ARM32,ARMv5T +immshifter \x31\x1\x20\x70 ARM32,ARMv5T [BXcc] -reg32 \3\x01\x2F\xFF\x10 ARM7 +reg32 \x62\x47\x0 THUMB,ARMv4T + +reg32 \3\x01\x2F\xFF\x10 ARM32,ARMv4T [CDP] -reg8,reg8 \300\1\x10\101 ARM7 +reg8,reg8 \300\1\x10\101 ARM32,ARMv4 -[CMFcc] +[CMNcc] +reglo,reglo \x6B\x42\xC0 THUMB,ARMv4T -[CMFEcc] +reg32,immshifter \x80\xF1\x10\x0F\x00 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEB\x10\x0F\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\x10\x0F\x00 THUMB32,WIDE,ARMv6T2 -[CMNcc] -reg32,reg32 \xC\x1\x60 ARM7 -reg32,reg32,reg32 \xD\x1\x60 ARM7 -reg32,reg32,imm \xE\x1\x60 ARM7 -reg32,imm \xF\x3\x60 ARM7 +reg32,reg32 \xC\x1\x60 ARM32,ARMv4 +reg32,reg32,shifterop \xE\x1\x60 ARM32,ARMv4 +reg32,immshifter \xF\x1\x60 ARM32,ARMv4 [CMPcc] -reg32,reg32 \xC\x1\x40 ARM7 -reg32,reg32,reg32 \xD\x1\x40 ARM7 -reg32,reg32,imm \xE\x1\x40 ARM7 -reg32,imm \xF\x3\x40 ARM7 +reglo,reglo \x6B\x42\x80 THUMB,ARMv4T +reg32,reg32 \x61\x45\x0 THUMB,ARMv4T -[CLZcc] -reg32,reg32 \x27\x01\x01 ARM7 +reglo,immshifter \x6B\x28\x0 THUMB,ARMv4T -[CNFcc] +reg32,immshifter \x80\xF1\xB0\x0F\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xEB\xB0\x0F\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\xB0\x0F\x00 THUMB32,WIDE,ARMv6T2 -[COScc] +reg32,reg32 \xC\x1\x40 ARM32,ARMv4 +reg32,reg32,shifterop \xE\x1\x40 ARM32,ARMv4 +reg32,immshifter \xF\x3\x40 ARM32,ARMv4 -[CPS] -[CPSID] -[CPSIE] +[CMFcc] +fpureg,fpureg \xA2\xE\x90 ARM32,FPA +fpureg,immshifter \xA2\xE\x90 ARM32,FPA -[DVFcc] +[CMFEcc] +fpureg,fpureg \xA2\xE\xC0 ARM32,FPA +fpureg,immshifter \xA2\xE\xC0 ARM32,FPA -[EORcc] -reg32,reg32,reg32 \4\x0\x20 ARM7 -reg32,reg32,reg32,reg32 \5\x0\x20 ARM7 -reg32,reg32,reg32,imm \6\x0\x20 ARM7 -reg32,reg32,imm \7\x2\x20 ARM7 +[STFcc] +fpureg,memam2 \xA0\xC\x00\x1\x0 ARM32,FPA -[EXPcc] +[LDFcc] +fpureg,memam2 \xA0\xC\x10\x1\x0 ARM32,FPA -[FDVcc] +[LFMcc] +fpureg,imm32,memam2 \xA0\xC\x10\x2\x0 ARM32,FPA +fpureg,immshifter,memam2 \xA0\xC\x10\x2\x0 ARM32,FPA -[FLTcc] +[CLZcc] +reg32,reg32 \x80\xFA\xB0\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32 \x32\x01\x6F\xF\x10 ARM32,ARMv4 -[FIXcc] +[CPS] +immshifter \x8F\xF3\xAF\x81\x00 THUMB32,ARMv6T2 +immshifter \x46\xF1\x2\x0\x0 ARM32,ARMv6 -[FMLcc] +[CPSID] +modeflags \x6C\xB6\x70 THUMB,ARMv6 +modeflags \x8F\xF3\xAF\x86\x00 THUMB32,WIDE,ARMv6T2 +modeflags,immshifter \x8F\xF3\xAF\x87\x00 THUMB32,WIDE,ARMv6T2 +modeflags \x46\xF1\xC\x0\x0 ARM32,ARMv6 +modeflags,immshifter \x46\xF1\xE\x0\x0 ARM32,ARMv6 -[FRDcc] +[CPSIE] +modeflags \x6C\xB6\x60 THUMB,ARMv6 +modeflags \x8F\xF3\xAF\x84\x00 THUMB32,WIDE,ARMv6T2 +modeflags,immshifter \x8F\xF3\xAF\x85\x00 THUMB32,WIDE,ARMv6T2 +modeflags \x46\xF1\x8\x0\x0 ARM32,ARMv6 +modeflags,immshifter \x46\xF1\xA\x0\x0 ARM32,ARMv6 + +[EORcc] +reglo,reglo \x6B\x40\x40 THUMB,ARMv4T + +reg32,immshifter \x80\xF0\x80\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x80\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x80\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF0\x80\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEA\x80\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\x80\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,reg32 \4\x0\x20 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\x20 ARM32,ARMv4 +reg32,reg32,immshifter \7\x2\x20 ARM32,ARMv4 [LDC] -reg32,reg32 \321\300\1\x11\101 ARM7 +reg32,reg32 \321\300\1\x11\101 ARM32,ARMv4 [LDMcc] -memam4,reglist \x26\x81 ARM7 +memam4,reglist \x69\xC8 THUMB,ARMv4T +reglo,reglist \x69\xC8 THUMB,ARMv4T + +memam4,reglist \x8C\xE8\x10\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reglist \x8C\xE8\x10\x0\x0 THUMB32,WIDE,ARMv6T2 + +memam4,reglist \x26\x81 ARM32,ARMv4 +reg32,reglist \x26\x81 ARM32,ARMv4 [LDRBTcc] +reg32,memam2 \x88\xF8\x10\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x17\x04\x70 ARM32,ARMv4 +reg32,immshifter \x17\x04\x70 ARM32,ARMv4 [LDRBcc] -reg32,memam2 \x17\x07\x10 ARM7 +reglo,memam3 \x65\x5C\x0\0 THUMB,ARMv4T +reglo,memam4 \x66\x78\x0\0 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x10\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x17\x04\x50 ARM32,ARMv4 [LDRcc] -reg32,memam2 \x17\x05\x10 ARM7 -; reg32,imm32 \x17\x05\x10 ARM7 -; reg32,reg32 \x18\x04\x10 ARM7 -; reg32,reg32,imm32 \x19\x04\x10 ARM7 -; reg32,reg32,reg32 \x20\x06\x10 ARM7 -; reg32,reg32,reg32,imm32 \x21\x06\x10 ARM7 +reglo,memam3 \x65\x58\x0\2 THUMB,ARMv4T +reglo,memam4 \x66\x68\x0\2 THUMB,ARMv4T +reglo,memam5 \x67\x98\x0\2 THUMB,ARMv4T +reglo,memam6 \x67\x48\x0\2 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x50\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x17\x04\x10 ARM32,ARMv4 [LDRHcc] -reg32,imm32 \x22\x50\xB0 ARM7 -reg32,reg32 \x23\x50\xB0 ARM7 -reg32,reg32,imm32 \x24\x50\xB0 ARM7 -reg32,reg32,reg32 \x25\x10\xB0 ARM7 +reglo,memam3 \x65\x5A\x0\1 THUMB,ARMv4T +reglo,memam4 \x66\x88\x0\1 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x30\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x22\x10\xB0 ARM32,ARMv4 [LDRSBcc] -reg32,imm32 \x22\x50\xD0 ARM7 -reg32,reg32 \x23\x50\xD0 ARM7 -reg32,reg32,imm32 \x24\x50\xD0 ARM7 -reg32,reg32,reg32 \x25\x10\xD0 ARM7 +reglo,memam3 \x65\x56\x0\0 THUMB,ARMv4T +reg32,memam2 \x88\xF9\x10\x0\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x22\x10\xD0 ARM32,ARMv4 +reg32,reg32 \x23\x50\xD0 ARM32,ARMv4 +reg32,reg32,imm32 \x24\x50\xD0 ARM32,ARMv4 +reg32,reg32,reg32 \x25\x10\xD0 ARM32,ARMv4 [LDRSHcc] -reg32,imm32 \x22\x50\xF0 ARM7 -reg32,reg32 \x23\x50\xF0 ARM7 -reg32,reg32,imm32 \x24\x50\xF0 ARM7 -reg32,reg32,reg32 \x25\x10\xF0 ARM7 +reglo,memam3 \x65\x5E\x0\1 THUMB,ARMv4T +reg32,memam2 \x88\xF9\x30\x0\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x22\x10\xF0 ARM32,ARMv4 [LDRTcc] +reg32,memam2 \x88\xF8\x50\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x17\x04\x30 ARM32,ARMv4 -[LDFcc] +[MCRcc] +regf,immshifter,reg32,regf,regf \x1C\xE\x0\x1 ARM32,ARMv4 +regf,immshifter,reg32,regf,regf,immshifter \x1C\xE\x0\x1 ARM32,ARMv4 -[LFMcc] -reg32,imm8,fpureg \xF0\x02\x01 FPA +[MCR2cc] +regf,immshifter,reg32,regf,regf \x1C\xFE\x0\x1 ARM32,ARMv5T +regf,immshifter,reg32,regf,regf,immshifter \x1C\xFE\x0\x1 ARM32,ARMv5T -[LGNcc] +[MRCcc] +regf,immshifter,reg32,regf,regf \x1C\xE\x10\x1 ARM32,ARMv4 +regf,immshifter,reg32,regf,regf,immshifter \x1C\xE\x10\x1 ARM32,ARMv4 -[LOGcc] +[MRC2cc] +regf,immshifter,reg32,regf,regf \x1C\xFE\x10\x1 ARM32,ARMv5T +regf,immshifter,reg32,regf,regf,immshifter \x1C\xFE\x10\x1 ARM32,ARMv5T + +[MCRRcc] +regf,immshifter,reg32,reg32,regf \x1D\xC\x40\x0 ARM32,ARMv5TE + +[MCRR2cc] +regf,immshifter,reg32,reg32,regf \x1D\xFC\x40\x0 ARM32,ARMv6 + +[MRRCcc] +regf,immshifter,reg32,reg32,regf \x1D\xC\x50\x0 ARM32,ARMv5TE -[MCR] -; reg32,mem32 \320\301\1\x13\110 ARM7 +[MRRC2cc] +regf,immshifter,reg32,reg32,regf \x1D\xFC\x50\x0 ARM32,ARMv6 [MLAcc] -reg32,reg32,reg32,reg32 \x15\x00\x20\x90 ARM7 +reg32,reg32,reg32,reg32 \x80\xFB\x0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x00\x20\x9 ARM32,ARMv4 [MOVcc] -; reg32,shifterop \x8\x0\0xd ARM7 -; reg32,immshifter \x8\x0\0xd ARM7 -; reg32,reg32,reg32 \x9\x1\xA0 ARM7 -; reg32,reg32,imm \xA\x1\xA0 ARM7 -; reg32,imm \xB\x3\xA0 ARM7 +reglo,reglo \x6B\x0\x0 THUMB,ARMv4T +reg32,reg32 \x61\x46\x00 THUMB,ARMv4T + +reglo,immshifter \x6B\x20\x0 THUMB,ARMv4T + +reg32,immshifter \x80\xF0\x4F\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \x80\xEA\x4F\x0\x0 THUMB32,WIDE,ARMv6T2 -[MRC] -; reg32,reg32 \321\301\1\x13\110 ARM7 +reg32,shifterop \x8\x1\xA0 ARM32,ARMv4 +reg32,reg32,shifterop \xA\x1\xA0 ARM32,ARMv4 +reg32,immshifter \xB\x1\xA0 ARM32,ARMv4 [MRScc] -reg32,reg32 \x10\x01\x0F ARM7 +reg32,regf \x96\xF3\xEF\x80\x0 THUMB32,ARMv6 +reg32,regf \x10\x01\x0F ARM32,ARMv4 [MSRcc] -reg32,reg32 \x11\x01\x29\xF0 ARM7 -regf,reg32 \x12\x01\x28\xF0 ARM7 -regf,imm \x13\x03\x28\xF0 ARM7 +regf,reg32 \x96\xF3\x80\x80\x0 THUMB32,ARMv6 -[MNFcc] - -[MUFcc] +regf,reg32 \x12\x01\x20\xF0 ARM32,ARMv4 +regf,immshifter \x13\x03\x20\xF0 ARM32,ARMv4 +regs,immshifter \x13\x03\x20\xF0 ARM32,ARMv4 [MULcc] -reg32,reg32,reg32 \x14\x00\x00\x90 ARM7 +reglo,reglo \x64\x43\x40 THUMB,ARMv4T +reglo,reglo,reglo \x64\x43\x40 THUMB,ARMv4T +reg32,reg32 \x80\xFB\x00\xF0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xFB\x00\xF0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x14\x00\x00\x90 ARM32,ARMv4 [MVFcc] -fpureg,fpureg \xF2 FPA -fpureg,immfpu \xF2 FPA +fpureg,fpureg \xA1\1\x1 ARM32,FPA +fpureg,immshifter \xA1\1\x1 ARM32,FPA [MVNcc] -; reg32,reg32 \x8\x0\0xf ARM7 -; reg32,reg32,reg32 \x9\x1\xE0 ARM7 -; reg32,reg32,imm \xA\x1\xE0 ARM7 -; reg32,imm \xB\x3\xE0 ARM7 +reglo,reglo \x6B\x43\xc0 THUMB,ARMv4T -[NOP] +reg32,immshifter \x80\xF0\x6F\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x6F\x0\x0 THUMB32,WIDE,ARMv6T2 -[ORRcc] -reg32,reg32,reg32 \4\x1\x80 ARM7 -reg32,reg32,reg32,reg32 \5\x1\x80 ARM7 -reg32,reg32,reg32,imm \6\x1\x80 ARM7 -reg32,reg32,imm \7\x3\x80 ARM7 +reg32,reg32 \x8\x1\xE0 ARM32,ARMv4 +reg32,reg32,shifterop \xA\x1\xE0 ARM32,ARMv4 +reg32,immshifter \xB\x1\xE0 ARM32,ARMv4 -[RDFcc] +[VMOVcc] +vreg,vreg \x90\xEE\xB0\xA\x40 THUMB32,VFPv2 +vreg,vreg \x40\xE\xB0\xA\x40 ARM32,VFPv2 -[RFScc] +reg32,vreg \x90\xEE\x10\xA\x10 THUMB32,VFPv2 +vreg,reg32 \x90\xEE\x00\xA\x10 THUMB32,VFPv2 +reg32,vreg \x40\xE\x10\xA\x10 ARM32,VFPv2 +vreg,reg32 \x40\xE\x00\xA\x10 ARM32,VFPv2 -[RFCcc] +reg32,reg32,vreg,vreg \x90\xEC\x50\xA\x10 THUMB32,VFPv2 +vreg,vreg,reg32,reg32 \x90\xEC\x40\xA\x10 THUMB32,VFPv2 +reg32,reg32,vreg,vreg \x40\xC\x50\xA\x10 ARM32,VFPv2 +vreg,vreg,reg32,reg32 \x40\xC\x40\xA\x10 ARM32,VFPv2 -[RMFcc] +reg32,reg32,vreg \x90\xEC\x50\xB\x10 THUMB32,VFPv2 +vreg,reg32,reg32 \x90\xEC\x40\xB\x10 THUMB32,VFPv2 +reg32,reg32,vreg \x40\xC\x50\xB\x10 ARM32,VFPv2 +vreg,reg32,reg32 \x40\xC\x40\xB\x10 ARM32,VFPv2 -[RPWcc] +[NOP] +void \x61\xBF\x0 THUMB,ARMv6T2 +void \x2F\x03\x20\xF0\x0 ARM32,ARMv6K +; Before ARMv6K use mov r0,r0 +void \x2F\xE1\xA0\x0\x0 ARM32,ARMv4 + +[ORNcc] +reg32,immshifter \x80\xF0\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,immshifter \x80\xF0\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEA\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\x60\x0\x0 THUMB32,ARMv6T2 -[RSBcc] -reg32,reg32,reg32 \4\x0\x60 ARM7 -reg32,reg32,reg32,reg32 \5\x0\x60 ARM7 -reg32,reg32,reg32,imm \6\x0\x60 ARM7 -reg32,reg32,imm \7\x2\x60 ARM7 +[ORRcc] +reglo,reglo \x6B\x43\x00 THUMB,ARMv4T -[RSCcc] -reg32,reg32,reg32 \4\x0\xE0 ARM7 -reg32,reg32,reg32,reg32 \5\x0\xE0 ARM7 -reg32,reg32,reg32,imm \6\x0\xE0 ARM7 -reg32,reg32,imm \7\x2\xE0 ARM7 +reg32,immshifter \x80\xF0\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF0\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEA\x40\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\x40\x0\x0 THUMB32,WIDE,ARMv6T2 -[RSFcc] +reg32,reg32,reg32 \4\x1\x80 ARM32,ARMv4 +reg32,reg32,reg32,reg32 \5\x1\x80 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x1\x80 ARM32,ARMv4 +reg32,reg32,immshifter \7\x3\x80 ARM32,ARMv4 -[RNDcc] +[RSBcc] +reglo,reglo,immzero \x6B\x42\x40 THUMB,ARMv4T -[POLcc] +reg32,immshifter \x80\xF1\xC0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xEB\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,immshifter \x80\xF1\xC0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xEB\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEB\xC0\x0\x0 THUMB32,ARMv6T2 + +reg32,reg32,reg32 \6\x0\x60 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\x60 ARM32,ARMv4 +reg32,reg32,immshifter \7\x0\x60 ARM32,ARMv4 + +[RSCcc] +reg32,reg32,reg32 \4\x0\xE0 ARM32,ARMv4 +reg32,reg32,reg32,reg32 \5\x0\xE0 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\xE0 ARM32,ARMv4 +reg32,reg32,immshifter \7\x2\xE0 ARM32,ARMv4 [SBCcc] -reg32,reg32,reg32 \4\x0\xC0 ARM7 -reg32,reg32,reg32,reg32 \5\x0\xC0 ARM7 -reg32,reg32,reg32,imm \6\x0\xC0 ARM7 -reg32,reg32,imm \7\x2\xC0 ARM7 +reglo,reglo \x6B\x41\x80 THUMB,ARMv4T + +reg32,immshifter \x80\xF1\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEB\x60\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\x60\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF1\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x80\xEB\x60\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEB\x60\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,reg32 \4\x0\xC0 ARM32,ARMv4 +reg32,reg32,reg32,reg32 \5\x0\xC0 ARM32,ARMv4 +reg32,reg32,reg32,imm \6\x0\xC0 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \6\x0\xC0 ARM32,ARMv4 +reg32,reg32,immshifter \7\x2\xC0 ARM32,ARMv4 [SFMcc] -reg32,imm8,fpureg \xF0\x02\x00 FPA +fpureg,imm32,memam2 \xA0\xC\x00\x2\x0 ARM32,FPA +fpureg,immshifter,memam2 \xA0\xC\x00\x2\x0 ARM32,FPA [SINcc] +fpureg,fpureg \xA1\1\x11 ARM32,FPA +fpureg,immshifter \xA1\1\x11 ARM32,FPA [SMLALcc] -reg32,reg32,reg32,reg32 \x16\x00\xE0\x90 ARM7 +reg32,reg32,reg32,reg32 \x85\xFB\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x00\xE0\x9 ARM32,ARMv4 [SMULLcc] -reg32,reg32,reg32,reg32 \x16\x00\xC0\x90 ARM7 - -[SQTcc] +reg32,reg32,reg32,reg32 \x85\xFB\x80\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x00\xC0\x9 ARM32,ARMv4 -[SUFcc] +[STMcc] +memam4,reglist \x69\xC0 THUMB,ARMv4T +reglo,reglist \x69\xC0 THUMB,ARMv4T -[STFcc] +memam4,reglist \x8C\xE8\x00\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reglist \x8C\xE8\x00\x0\x0 THUMB32,WIDE,ARMv6T2 -[STMcc] -memam4,reglist \x26\x80 ARM7 +memam4,reglist \x26\x80 ARM32,ARMv4 +reg32,reglist \x26\x80 ARM32,ARMv4 [STRcc] -reg32,memam2 \x17\x04\x00 ARM7 -; reg32,imm32 \x17\x05\x00 ARM7 -; reg32,reg32 \x18\x04\x00 ARM7 -; reg32,reg32,imm32 \x19\x04\x00 ARM7 -; reg32,reg32,reg32 \x20\x06\x00 ARM7 -; reg32,reg32,reg32,imm32 \x21\x06\x00 ARM7 +reglo,memam3 \x65\x50\x0\2 THUMB,ARMv4T +reglo,memam4 \x66\x60\x0\2 THUMB,ARMv4T +reglo,memam5 \x67\x90\x0\2 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x40\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x17\x04\x00 ARM32,ARMv4 [STRBcc] -reg32,memam2 \x17\x06\x00 ARM7 +reglo,memam3 \x65\x54\x0\0 THUMB,ARMv4T +reglo,memam4 \x66\x70\x0\0 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x00\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x17\x04\x40 ARM32,ARMv4 [STRBTcc] +reg32,memam2 \x88\xF8\x00\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x17\x04\x60 ARM32,ARMv4 +reg32,immshifter \x17\x04\x60 ARM32,ARMv4 -; A dummy since it is parsed as STR{cond}H [STRHcc] -reg32,imm32 \x22\x40\xB0 ARM7 -reg32,reg32 \x23\x40\xB0 ARM7 -reg32,reg32,imm32 \x24\x40\xB0 ARM7 -reg32,reg32,reg32 \x25\x00\xB0 ARM7 +reglo,memam3 \x65\x52\x0\1 THUMB,ARMv4T +reglo,memam4 \x66\x80\x0\1 THUMB,ARMv4T +reg32,memam2 \x88\xF8\x20\x0\x0\0 THUMB32,WIDE,ARMv6T2 +reg32,memam2 \x22\x00\xB0 ARM32,ARMv4 [STRTcc] +reg32,memam2 \x88\xF8\x40\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x17\x04\x20 ARM32,ARMv4 [SUBcc] -reg32,reg32,shifterop \4\x0\x40 ARM7 -reg32,reg32,immshifter \4\x0\x40 ARM7 -reg32,reg32,reg32 \4\x0\x40 ARM7 -; reg32,reg32,reg32,reg32 \5\x0\x40 ARM7 -; reg32,reg32,reg32,imm \6\x0\x40 ARM7 -; reg32,reg32,imm \7\x2\x40 ARM7 +regsp,immshifter \x64\xB0\x80 THUMB,ARMv4T +regsp,regsp,immshifter \x64\xB0\x80 THUMB,ARMv4T +reglo,reglo \x60\x1A\x0 THUMB,ARMv4T +reglo,reglo,reglo \x60\x1A\x0 THUMB,ARMv4T + +reglo,immshifter \x60\x1E\x0 THUMB,ARMv4T +reglo,reglo,immshifter \x60\x1E\x0 THUMB,ARMv4T +reglo,imm8 \x6B\x38\x0 THUMB,ARMv4T +reglo,immshifter \x6B\x38\x0 THUMB,ARMv4T + +reg32,immshifter \x80\xF1\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xEB\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEB\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x80\xF1\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xEB\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEB\xA0\x0\x0 THUMB32,WIDE,ARMv6T2 + +reg32,reg32,shifterop \x4\x0\x40 ARM32,ARMv4 +reg32,reg32,immshifter \x4\x0\x40 ARM32,ARMv4 +reg32,reg32,reg32 \x4\x0\x40 ARM32,ARMv4 +reg32,reg32,reg32,shifterop \x6\x0\x40 ARM32,ARMv4 [SWIcc] -imm \2\x0F ARM7 +; Old alias for SVC [SWPcc] -reg32,reg32,reg32 \x27\x01\x90 ARM7 +reg32,reg32,memam2 \x27\x10\x09 ARM32,ARMv4 [SWPBcc] -reg32,reg32,reg32 \x27\x01\x90 ARM7 - -[TANcc] +reg32,reg32,memam2 \x27\x14\x09 ARM32,ARMv4 [TEQcc] -reg32,reg32 \xC\x1\x20 ARM7 -reg32,reg32,reg32 \xD\x1\x20 ARM7 -reg32,reg32,imm \xE\x1\x20 ARM7 -reg32,imm \xF\x3\x20 ARM7 +reg32,immshifter \x80\xF0\x90\x0F\x00 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x90\x0F\x00 THUMB32,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x90\x0F\x00 THUMB32,ARMv6T2 + +reg32,reg32 \xC\x1\x20 ARM32,ARMv4 +reg32,reg32,reg32 \xD\x1\x20 ARM32,ARMv4 +reg32,reg32,shifterop \xE\x1\x20 ARM32,ARMv4 +reg32,immshifter \xF\x3\x20 ARM32,ARMv4 [TSTcc] -reg32,reg32 \xC\x1\x00 ARM7 -reg32,reg32,reg32 \xD\x1\x00 ARM7 -reg32,reg32,imm \xE\x1\x00 ARM7 -reg32,imm \xF\x3\x00 ARM7 +reglo,reglo \x6B\x42\x00 THUMB,ARMv4T + +reg32,immshifter \x80\xF0\x10\x0F\x00 THUMB32,ARMv6T2 +reg32,reg32 \x80\xEA\x10\x0F\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x80\xEA\x10\x0F\x00 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \xC\x1\x00 ARM32,ARMv4 +reg32,reg32,reg32 \xD\x1\x00 ARM32,ARMv4 +reg32,reg32,shifterop \xE\x1\x00 ARM32,ARMv4 +reg32,immshifter \xF\x3\x00 ARM32,ARMv4 [UMLALcc] -reg32,reg32,reg32,reg32 \x16\x00\xA0\x90 ARM7 +reg32,reg32,reg32,reg32 \x85\xFB\xE0\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x00\xA0\x9 ARM32,ARMv4 [UMULLcc] -reg32,reg32,reg32,reg32 \x16\x00\x80\x90 ARM7 +reg32,reg32,reg32,reg32 \x85\xFB\xA0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x00\x80\x9 ARM32,ARMv4 [WFScc] +reg32 \xA2\xE\x2 ARM32,FPA ; EDSP instructions [LDRDcc] - -[MCRRcc] - -[MRRCcc] +reg32,reg32,memam2 \x89\xE8\x50\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,memam2 \x19\x0\x0\x0\xD0 ARM32,ARMv4 [PLD] +memam2 \x87\xF8\x10\xF0\x0 THUMB32,ARMv6T2 +memam2 \x25\xF5\x50\xF0\x0 ARM32,ARMv5TE + +[PLDW] +memam2 \x87\xF8\x30\xF0\x0 THUMB32,ARMv7 +memam2 \x25\xF5\x10\xF0\x0 ARM32,ARMv7 [QADDcc] +reg32,reg32,reg32 \x82\xFA\x80\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x1A\x01\x00\x05 ARM32,ARMv5TE [QDADDcc] +reg32,reg32,reg32 \x82\xFA\x80\xF0\x90 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x1A\x01\x40\x05 ARM32,ARMv5TE [QDSUBcc] +reg32,reg32,reg32 \x82\xFA\x80\xF0\xB0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x1A\x01\x60\x05 ARM32,ARMv5TE [QSUBcc] +reg32,reg32,reg32 \x82\xFA\x80\xF0\xA0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x1A\x01\x20\x05 ARM32,ARMv5TE [SMLABBcc] +reg32,reg32,reg32,reg32 \x15\x01\x00\x8 ARM32,ARMv5TE [SMLABTcc] +reg32,reg32,reg32,reg32 \x15\x01\x00\xC ARM32,ARMv5TE [SMLATBcc] +reg32,reg32,reg32,reg32 \x15\x01\x00\xA ARM32,ARMv5TE [SMLATTcc] +reg32,reg32,reg32,reg32 \x15\x01\x00\xE ARM32,ARMv5TE [SMLALBBcc] +reg32,reg32,reg32,reg32 \x16\x01\x40\x8 ARM32,ARMv5TE [SMLALBTcc] +reg32,reg32,reg32,reg32 \x16\x01\x40\xC ARM32,ARMv5TE [SMLALTBcc] +reg32,reg32,reg32,reg32 \x16\x01\x40\xA ARM32,ARMv5TE [SMLALTTcc] +reg32,reg32,reg32,reg32 \x16\x01\x40\xE ARM32,ARMv5TE [SMLAWBcc] +reg32,reg32,reg32,reg32 \x80\xFB\x30\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x1\x20\x8 ARM32,ARMv5TE [SMLAWTcc] +reg32,reg32,reg32,reg32 \x80\xFB\x30\x0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x1\x20\xC ARM32,ARMv5TE + +[VLDMcc] +memam4,reglist \x94\xEC\x10\xA THUMB32,VFPv2 +reg32,reglist \x94\xEC\x10\xA THUMB32,VFPv2 +memam4,reglist \x44\xC\x10\xA ARM32,VFPv2 +reg32,reglist \x44\xC\x10\xA ARM32,VFPv2 + +[VSTMcc] +memam4,reglist \x94\xEC\x00\xA THUMB32,VFPv2 +reg32,reglist \x94\xEC\x00\xA THUMB32,VFPv2 +memam4,reglist \x44\xC\x00\xA ARM32,VFPv2 +reg32,reglist \x44\xC\x00\xA ARM32,VFPv2 + +[VPOP] +reglist \x94\xEC\xBD\xA THUMB32,VFPv2 +reglist \x44\xC\xBD\xA ARM32,VFPv2 + +[VPUSH] +reglist \x94\xED\x2D\xA THUMB32,VFPv2 +reglist \x44\xD\x2D\xA ARM32,VFPv2 + +[VLDRcc] +vreg,memam2 \x95\xED\x10\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x10\xA ARM32,VFPv2 + +[VSTRcc] +vreg,memam2 \x95\xED\x0\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x0\xA ARM32,VFPv2 [SMULBBcc] +reg32,reg32,reg32 \x15\x01\x60\x8\x0 ARM32,ARMv5TE [SMULBTcc] +reg32,reg32,reg32 \x15\x01\x60\xC\x0 ARM32,ARMv5TE [SMULTBcc] +reg32,reg32,reg32 \x15\x01\x60\xA\x0 ARM32,ARMv5TE [SMULTTcc] +reg32,reg32,reg32 \x15\x01\x60\xE\x0 ARM32,ARMv5TE [SMULWBcc] +reg32,reg32,reg32 \x14\x1\x20\xA0 ARM32,ARMv5TE [SMULWTcc] +reg32,reg32,reg32 \x14\x1\x20\xE0 ARM32,ARMv5TE [STRDcc] +reg32,reg32,memam2 \x89\xE8\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,memam2 \x19\x0\x0\x0\xF0 ARM32,ARMv4 -; -; vfp instructions -; -[FABSDcc] +[LDRHTcc] +reg32,memam2 \x88\xF8\x30\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x19\x0\x30\x0\xB0 ARM32,ARMv4 -[FABSScc] +[STRHTcc] +reg32,memam2 \x88\xF8\x20\xE\x0\0 THUMB32,ARMv6T2 -[FADDDcc] +reg32,memam2 \x88\xF8\x20\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x1E\x0\x20\x0\xB0 ARM32,ARMv4 -[FADDScc] +[LDRSBTcc] +reg32,memam2 \x88\xF9\x10\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x1E\x0\x30\x0\xD0 ARM32,ARMv4 -[FCMPDcc] +[LDRSHTcc] +reg32,memam2 \x88\xF9\x30\xE\x0\0 THUMB32,ARMv6T2 +reg32,memam2 \x1E\x0\x30\x0\xF0 ARM32,ARMv4 -[FCMPEDcc] +[FSTDcc] +vreg,memam2 \x95\xED\x0\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x0\xA ARM32,VFPv2 -[FCMPEScc] +[FSTMcc] +memam4,reglist \x94\xEC\x00\xA THUMB32,VFPv2 +reg32,reglist \x94\xEC\x00\xA THUMB32,VFPv2 +memam4,reglist \x44\xC\x00\xA ARM32,VFPv2 +reg32,reglist \x44\xC\x00\xA ARM32,VFPv2 -[FCMPEZDcc] +[FSTScc] +vreg,memam2 \x95\xED\x0\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x0\xA ARM32,VFPv2 -[FCMPEZScc] +; ARMv6 -[FCMPScc] +[BFCcc] +reg32,immshifter,immshifter \x84\xF3\x6F\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter,imm32 \x84\xF3\x6F\x0\x0 THUMB32,ARMv6T2 -[FCMPZDcc] +reg32,immshifter,immshifter \x2D\x7\xC0\x0\x1F ARM32,ARMv4 +reg32,immshifter,imm32 \x2D\x7\xC0\x0\x1F ARM32,ARMv4 -[FCMPZScc] +[BFIcc] +reg32,reg32,immshifter,immshifter \x84\xF3\x60\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,immshifter,imm32 \x84\xF3\x60\x0\x0 THUMB32,ARMv6T2 -[FCPYDcc] +reg32,reg32,immshifter,immshifter \x2D\x7\xC0\x0\x10 ARM32,ARMv4 +reg32,reg32,immshifter,imm32 \x2D\x7\xC0\x0\x10 ARM32,ARMv4 -[FCPYScc] +[CLREX] +void \x80\xF3\xBF\x8F\x2F THUMB32,ARMv7 +void \x2F\xF5\x7F\xF0\x1F ARM32,ARMv6K -[FCVTDScc] +[LDREXcc] +reg32,memam6 \x8A\xE8\x50\x0F\x00 THUMB32,ARMv6T2 +reg32,memam6 \x18\x01\x90\x0F\x9F ARM32,ARMv4 -[FCVTSDcc] +[LDREXBcc] +reg32,memam6 \x8A\xE8\xD0\x0F\x4F THUMB32,ARMv7 +reg32,memam6 \x18\x01\xD0\x0F\x9F ARM32,ARMv4 -[FDIVDcc] +[LDREXDcc] +reg32,reg32,memam6 \x8A\xE8\xD0\x00\x7F THUMB32,ARMv7 +reg32,reg32,memam6 \x18\x01\xB0\x0F\x9F ARM32,ARMv4 -[FDIVScc] +[LDREXHcc] +reg32,memam6 \x8A\xE8\xD0\x0F\x5F THUMB32,ARMv7 +reg32,memam6 \x18\x01\xF0\x0F\x9F ARM32,ARMv4 -[FLDDcc] +[STREXcc] +reg32,reg32,memam6 \x8B\xE8\x40\x00\x00 THUMB32,ARMv6T2 +reg32,reg32,memam6 \x18\x01\x80\x0F\x90 ARM32,ARMv4 -[FLDMcc] +[STREXBcc] +reg32,reg32,memam6 \x8B\xE8\xC0\x0F\x40 THUMB32,ARMv7 +reg32,reg32,memam6 \x18\x01\xC0\x0F\x90 ARM32,ARMv4 -[FLDScc] +[STREXDcc] +reg32,reg32,reg32,memam6 \x8B\xE8\xC0\x00\x70 THUMB32,ARMv7 +reg32,reg32,reg32,memam6 \x18\x01\xA0\x0F\x90 ARM32,ARMv4 -[FMACDcc] +[STREXHcc] +reg32,reg32,memam6 \x8B\xE8\xC0\x0F\x50 THUMB32,ARMv7 +reg32,reg32,memam6 \x18\x01\xE0\x0F\x90 ARM32,ARMv4 -[FMACScc] +[MLScc] +reg32,reg32,reg32,reg32 \x80\xFB\x0\x0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x00\x60\x9 ARM32,ARMv6T2 -[FMDHRcc] +[PKHBTcc] +reg32,reg32,reg32 \x80\xEA\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\xC0\x0\x0 THUMB32,ARMv6T2 -[FMDLRcc] +reg32,reg32,reg32 \x16\x6\x80\x1 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x6\x80\x1 ARM32,ARMv6 -[FMRDHcc] +[PKHTBcc] +reg32,reg32,reg32 \x80\xEA\xC0\x0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x80\xEA\xC0\x0\x10 THUMB32,ARMv6T2 -[FMRDLcc] +reg32,reg32,reg32 \x16\x6\x80\x1 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x6\x80\x5 ARM32,ARMv6 -[FMRScc] +[PLI] +memam2 \x87\xF9\x10\xF0\x0 THUMB32,ARMv7 +memam2 \x25\xF4\x50\xF0\x0 ARM32,ARMv7 -[FMRXcc] +[QADD16cc] +reg32,reg32,reg32 \x80\xFA\x90\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xF1 ARM32,ARMv6 +[QADD8cc] +reg32,reg32,reg32 \x80\xFA\x80\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xF9 ARM32,ARMv6 +[QASXcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xF3 ARM32,ARMv6 +[QSAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xF5 ARM32,ARMv6 +[QSUB16cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xF7 ARM32,ARMv6 +[QSUB8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x10 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x20\xFF ARM32,ARMv6 -[FMSCDcc] +[RBITcc] +reg32,reg32 \x80\xFA\x90\xF0\xA0 THUMB32,ARMv6T2 +reg32,reg32 \x32\x6\xFF\xF\x30 ARM32,ARMv6T2 -[FMSCScc] +[REVcc] +reglo,reglo \x61\xBA\x00 THUMB,ARMv6 +reg32,reg32 \x80\xFA\x90\xF0\x80 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x32\x6\xBF\xF\x30 ARM32,ARMv6 -[FMSRcc] +[REV16cc] +reglo,reglo \x61\xBA\x40 THUMB,ARMv6 +reg32,reg32 \x80\xFA\x90\xF0\x90 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x32\x6\xBF\xF\xB0 ARM32,ARMv6 -[FMSTATcc] +[REVSHcc] +reglo,reglo \x61\xBA\xC0 THUMB,ARMv6 +reg32,reg32 \x80\xFA\x90\xF0\xB0 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x32\x6\xFF\xF\xB0 ARM32,ARMv6 -[FMULDcc] +[SADD16cc] +reg32,reg32,reg32 \x80\xFA\90\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xF1 ARM32,ARMv6 -[FMULScc] +[SADD8cc] +reg32,reg32,reg32 \x80\xFA\80\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xF9 ARM32,ARMv6 -[FMXRcc] +[SASXcc] +reg32,reg32,reg32 \x80\xFA\A0\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xF3 ARM32,ARMv6 -[FNEGDcc] +[SBFXcc] +reg32,reg32,immshifter,immshifter \x84\xF3\x40\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,immshifter,immshifter \x2D\x7\xA0\x0\x50 ARM32,ARMv6T2 -[FNEGScc] +[SELcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x80\xFB ARM32,ARMv6 -[FNMACDcc] +[SETEND] +immshifter \x2B\xF1\x01\x0\x0 ARM32,ARMv6 -[FNMACScc] +[SEVcc] +void \x64\xBF\x40 THUMB,ARMv7 +void \x2F\x3\x20\xF0\x4 ARM32,ARMv6K -[FNMSCDcc] +[ASRcc] +reglo,immshifter \x60\x1\x0 THUMB,ARMv4T +reglo,reglo,immshifter \x60\x1\x0 THUMB,ARMv4T +reglo,reglo \x6B\x41\x0 THUMB,ARMv4T -[FNMSCScc] +reg32,immshifter \x82\xEA\x4F\x0\x20 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x82\xEA\x4F\x0\x20 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xFA\x40\xF0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xFA\x40\xF0\x0 THUMB32,WIDE,ARMv6T2 -[FNMULDcc] +reg32,reg32,reg32 \x30\x1\xA0\x0\x50 ARM32,ARMv4 +reg32,reg32,immshifter \x30\x1\xA0\x0\x40 ARM32,ARMv4 -[FNMULScc] +[LSRcc] +reglo,immshifter \x60\x8\x0 THUMB,ARMv4T +reglo,reglo,immshifter \x60\x8\x0 THUMB,ARMv4T +reglo,reglo \x6B\x40\xC0 THUMB,ARMv4T -[FSITODcc] +reg32,immshifter \x82\xEA\x4F\x0\x10 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x82\xEA\x4F\x0\x10 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xFA\x20\xF0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xFA\x20\xF0\x0 THUMB32,WIDE,ARMv6T2 -[FSITOScc] +reg32,reg32,reg32 \x30\x1\xA0\x0\x30 ARM32,ARMv4 +reg32,reg32,immshifter \x30\x1\xA0\x0\x20 ARM32,ARMv4 -[FSQRTDcc] +[LSLcc] +reglo,immshifter \x60\x0\x0 THUMB,ARMv4T +reglo,reglo,immshifter \x60\x0\x0 THUMB,ARMv4T +reglo,reglo \x6B\x40\x80 THUMB,ARMv4T -[FSQRTScc] +reg32,immshifter \x82\xEA\x4F\x0\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x82\xEA\x4F\x0\x00 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xFA\x60\xF0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xFA\x60\xF0\x0 THUMB32,WIDE,ARMv6T2 -[FSTDcc] +reg32,reg32,reg32 \x30\x1\xA0\x0\x10 ARM32,ARMv4 +reg32,reg32,immshifter \x30\x1\xA0\x0\x00 ARM32,ARMv4 -[FSTMcc] +[RORcc] +reglo,reglo \x6B\x41\xC0 THUMB,ARMv4T -[FSTScc] +reg32,immshifter \x82\xEA\x4F\x0\x30 THUMB32,WIDE,ARMv6T2 +reg32,reg32,immshifter \x82\xEA\x4F\x0\x30 THUMB32,WIDE,ARMv6T2 +reg32,reg32 \x80\xFA\x60\xF0\x0 THUMB32,WIDE,ARMv6T2 +reg32,reg32,reg32 \x80\xFA\x60\xF0\x0 THUMB32,WIDE,ARMv6T2 -[FSUBDcc] +reg32,reg32,reg32 \x30\x1\xA0\x0\x70 ARM32,ARMv4 +reg32,reg32,immshifter \x30\x1\xA0\x0\x60 ARM32,ARMv4 -[FSUBScc] +[RRXcc] +reg32,reg32 \x80\xEA\x4F\x00\x30 THUMB32,ARMv6T2 +reg32,reg32 \x30\x1\xA0\x0\x60 ARM32,ARMv4 -[FTOSIDcc] +[UMAALcc] +reg32,reg32,reg32,reg32 \x85\xFB\xE0\x0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x0\x40\x9 ARM32,ARMv6 -[FTOSIScc] +[SHADD16cc] +reg32,reg32,reg32 \x80\xFA\x90\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xF1 ARM32,ARMv6 -[FTOUIDcc] +[SHADD8cc] +reg32,reg32,reg32 \x80\xFA\x80\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xF9 ARM32,ARMv6 -[FTOUIScc] +[SHASXcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xF3 ARM32,ARMv6 -[FUITODcc] +[SHSAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xF5 ARM32,ARMv6 -[FUITOScc] +[SHSUB16cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xF7 ARM32,ARMv6 -[FMDRRcc] +[SHSUB8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x20 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x30\xFF ARM32,ARMv6 -[FMRRDcc] +[SMLADcc] +reg32,reg32,reg32,reg32 \x80\xFB\x20\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x7\x00\x1 ARM32,ARMv6 -; ARMv6 +[SMLALDcc] +reg32,reg32,reg32,reg32 \x85\xFB\xC0\x0\xC0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x7\x40\x1 ARM32,ARMv4 -[BFCcc] +[SMLSDcc] +reg32,reg32,reg32,reg32 \x80\xFB\x40\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x7\x00\x5 ARM32,ARMv6 -[BFIcc] +[SMLSLDcc] +reg32,reg32,reg32,reg32 \x85\xFB\xD0\x0\xC0 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x16\x7\x40\x5 ARM32,ARMv6 -[CLREX] +[SMMLAcc] +reg32,reg32,reg32,reg32 \x80\xFB\x50\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x7\x50\x1 ARM32,ARMv6 -[LDREXcc] -[LDREXBcc] -[LDREXDcc] -[LDREXHcc] +[SMMLScc] +reg32,reg32,reg32,reg32 \x80\xFB\x60\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x7\x50\xD ARM32,ARMv6 -[MLScc] +[SMMULcc] +reg32,reg32,reg32 \x80\xFB\x50\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x15\x7\x50\x1\xF ARM32,ARMv6 -[PKHcc] +[SMUADcc] +reg32,reg32,reg32 \x80\xFB\x20\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x15\x7\x00\x1\xF ARM32,ARMv6 -[PLI] +[SMUSDcc] +reg32,reg32,reg32 \x80\xFB\x40\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x15\x7\x00\x5\xF ARM32,ARMv6 -[QADD16cc] -[QADD8cc] -[QASXcc] -[QSAXcc] -[QSUB16cc] -[QSUB8cc] +[SRScc] -[RBITcc] +[SSATcc] +reg32,immshifter,reg32 \x83\xF3\x00\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter,reg32,shifterop \x83\xF3\x00\x0\x0 THUMB32,ARMv6T2 -[REVcc] -[REV16cc] -[REVSHcc] +reg32,immshifter,reg32 \x2A\x6\xA0\x0\x10 ARM32,ARMv6 +reg32,immshifter,reg32,shifterop \x2A\x6\xA0\x0\x10 ARM32,ARMv6 -[SADD16cc] -[SADD8cc] -[SASXcc] +[SSAT16cc] +reg32,immshifter,reg32 \x83\xF3\x20\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter,reg32 \x2A\x6\xA0\xF\x30 ARM32,ARMv6 -[SBFXcc] +[SSAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xF5 ARM32,ARMv6 -[SELcc] +[SSUB16cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xF7 ARM32,ARMv6 -[SETEND] +[SSUB8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x0 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x10\xFF ARM32,ARMv6 -[SEVcc] +[SXTABcc] +reg32,reg32,reg32 \x86\xFA\x40\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x40\xF0\x80 THUMB32,ARMv6T2 -[ASRcc] +reg32,reg32,reg32 \x16\x06\xA0\x07 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x06\xA0\x07 ARM32,ARMv6 -[LSRcc] +[SXTAB16cc] +reg32,reg32,reg32 \x86\xFA\x20\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x20\xF0\x80 THUMB32,ARMv6T2 -[LSLcc] +reg32,reg32,reg32 \x16\x06\x80\x07 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x06\x80\x07 ARM32,ARMv6 -[RORcc] +[SXTAHcc] +reg32,reg32,reg32 \x86\xFA\x00\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x00\xF0\x80 THUMB32,ARMv6T2 -[SHADD16cc] -[SHADD8cc] -[SHASXcc] -[SHSAXcc] -[SHSUB16cc] -[SHSUB8cc] +reg32,reg32,reg32 \x16\x06\xB0\x07 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x06\xB0\x07 ARM32,ARMv6 -[SMLADcc] -[SMLALDcc] -[SMLSDcc] -[SMLSLDcc] -[SMMLAcc] -[SMMLScc] -[SMMULcc] -[SMUADcc] -[SMUSDcc] +[UBFXcc] +reg32,reg32,immshifter,immshifter \x84\xF3\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,reg32,immshifter,immshifter \x2D\x7\xE0\x0\x50 ARM32,ARMv4 -[SRScc] +[UXTABcc] +reg32,reg32,reg32 \x86\xFA\x50\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x50\xF0\x80 THUMB32,ARMv6T2 -[SSATcc] -[SSAT16cc] -[SSAXcc] +reg32,reg32,reg32 \x16\x6\xE0\x7 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x6\xE0\x7 ARM32,ARMv6 -[SSUB16cc] -[SSUB8cc] +[UXTAB16cc] +reg32,reg32,reg32 \x86\xFA\x30\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x30\xF0\x80 THUMB32,ARMv6T2 -[STREXcc] -[STREXBcc] -[STREXDcc] -[STREXHcc] +reg32,reg32,reg32 \x86\xFA\x40\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x40\xF0\x80 THUMB32,ARMv6T2 + +reg32,reg32,reg32 \x16\x6\xC0\x7 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x6\xC0\x7 ARM32,ARMv6 + +[UXTAHcc] +reg32,reg32,reg32 \x86\xFA\x10\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,reg32,shifterop \x86\xFA\x10\xF0\x80 THUMB32,ARMv6T2 + +reg32,reg32,reg32 \x16\x6\xF0\x7 ARM32,ARMv6 +reg32,reg32,reg32,shifterop \x16\x6\xF0\x7 ARM32,ARMv6 -[SXTABcc] -[SXTAB16cc] -[SXTAHcc] [SXTBcc] +reglo,reglo \x61\xB2\x40 THUMB,ARMv6 + +reg32,reg32 \x86\xFA\x4F\xF0\x80 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x4F\xF0\x80 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \x1B\x6\xAF\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\xAF\x7 ARM32,ARMv6 + [SXTB16cc] +reg32,reg32 \x86\xFA\x2F\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x2F\xF0\x80 THUMB32,ARMv6T2 + +reg32,reg32 \x1B\x6\x8F\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\x8F\x7 ARM32,ARMv6 + +[SXTHcc] +reglo,reglo \x61\xB2\x00 THUMB,ARMv6 + +reg32,reg32 \x86\xFA\x0F\xF0\x80 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x0F\xF0\x80 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \x1B\x6\xBF\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\xBF\x7 ARM32,ARMv6 [UXTBcc] +reglo,reglo \x61\xB2\xC0 THUMB,ARMv6 + +reg32,reg32 \x86\xFA\x5F\xF0\x80 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x5F\xF0\x80 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \x1B\x6\xEF\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\xEF\x7 ARM32,ARMv6 + +[UXTB16cc] +reg32,reg32 \x86\xFA\x3F\xF0\x80 THUMB32,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x3F\xF0\x80 THUMB32,ARMv6T2 + +reg32,reg32 \x1B\x6\xCF\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\xCF\x7 ARM32,ARMv6 + [UXTHcc] +reglo,reglo \x61\xB2\x80 THUMB,ARMv6 -[SXTHcc] +reg32,reg32 \x86\xFA\x1F\xF0\x80 THUMB32,WIDE,ARMv6T2 +reg32,reg32,shifterop \x86\xFA\x1F\xF0\x80 THUMB32,WIDE,ARMv6T2 + +reg32,reg32 \x1B\x6\xFF\x7 ARM32,ARMv6 +reg32,reg32,shifterop \x1B\x6\xFF\x7 ARM32,ARMv6 [UADD16cc] +reg32,reg32,reg32 \x80\xFA\x90\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xF1 ARM32,ARMv6 + [UADD8cc] -[UASXcc] +reg32,reg32,reg32 \x80\xFA\x80\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xF9 ARM32,ARMv6 -[UBFXcc] +[UASXcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xF3 ARM32,ARMv6 [UHADD16cc] +reg32,reg32,reg32 \x80\xFA\x90\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xF1 ARM32,ARMv6 + [UHADD8cc] +reg32,reg32,reg32 \x80\xFA\x80\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xF9 ARM32,ARMv6 + [UHASXcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xF3 ARM32,ARMv6 + [UHSAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xF5 ARM32,ARMv6 + [UHSUB16cc] -[UHSUB8cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xF7 ARM32,ARMv6 -[UMAALcc] +[UHSUB8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x60 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x70\xFF ARM32,ARMv6 [UQADD16cc] +reg32,reg32,reg32 \x80\xFA\x90\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xF1 ARM32,ARMv6 + [UQADD8] +reg32,reg32,reg32 \x80\xFA\x80\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xF9 ARM32,ARMv6 + [UQASXcc] +reg32,reg32,reg32 \x80\xFA\xA0\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xF3 ARM32,ARMv6 + [UQSAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xF5 ARM32,ARMv6 [UQSUB16cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xF7 ARM32,ARMv6 + [UQSUB8cc] -[UQSAD8cc] -[UQSADA8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x50 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x60\xFF ARM32,ARMv6 + +[USAD8cc] +reg32,reg32,reg32 \x80\xFB\x70\xF0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x15\x07\x80\x01\xF ARM32,ARMv6 + +[USADA8cc] +reg32,reg32,reg32,reg32 \x80\xFB\x70\x0\x00 THUMB32,ARMv6T2 +reg32,reg32,reg32,reg32 \x15\x07\x80\x01 ARM32,ARMv6 [USATcc] +reg32,immshifter,reg32 \x83\xF3\x80\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter,reg32,shifterop \x83\xF3\x80\x0\x0 THUMB32,ARMv6T2 + +reg32,immshifter,reg32 \x2A\x6\xE0\x0\x10 ARM32,ARMv6 +reg32,immshifter,reg32,shifterop \x2A\x6\xE0\x0\x10 ARM32,ARMv6 + [USAT16cc] +reg32,immshifter,reg32 \x83\xF3\xA0\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter,reg32 \x2A\x6\xE0\xF\x30 ARM32,ARMv6 + [USAXcc] +reg32,reg32,reg32 \x80\xFA\xE0\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xF5 ARM32,ARMv6 [USUB16cc] -[USUB8cc] +reg32,reg32,reg32 \x80\xFA\xD0\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xF7 ARM32,ARMv6 -[UXTABcc] -[UXTAB16cc] -[UXTAHcc] -[UXTB16cc] +[USUB8cc] +reg32,reg32,reg32 \x80\xFA\xC0\xF0\x40 THUMB32,ARMv6T2 +reg32,reg32,reg32 \x16\x06\x50\xFF ARM32,ARMv6 [WFEcc] +void \x64\xBF\x20 THUMB,ARMv7 +void \x2F\x3\x20\xF0\x2 ARM32,ARMv6K + [WFIcc] +void \x64\xBF\x30 THUMB,ARMv7 +void \x2F\x3\x20\xF0\x3 ARM32,ARMv6K + [YIELDcc] +void \x64\xBF\x10 THUMB,ARMv7 +void \x2F\x3\x20\xF0\x1 ARM32,ARMv6K + +; +; vfp instructions +; +[FABSDcc] +vreg,vreg \x92\xEE\xB0\xA\xC0\0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB0\xA\xC0\0 ARM32,VFPv2 + +[FABSScc] +vreg,vreg \x92\xEE\xB0\xA\xC0\1 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB0\xA\xC0\1 ARM32,VFPv2 + +[FADDDcc] +vreg,vreg,vreg \x92\xEE\x30\xA\x0\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x0\0 ARM32,VFPv2 + +[FADDScc] +vreg,vreg,vreg \x92\xEE\x30\xA\x0\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x0\1 ARM32,VFPv2 + +[FCMPDcc] +vreg,vreg \x92\xEE\xB4\xA\x40\0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\x40\0 ARM32,VFPv2 + +[FCMPScc] +vreg,vreg \x92\xEE\xB4\xA\x40\1 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\x40\1 ARM32,VFPv2 + +[FCMPEDcc] +vreg,vreg \x92\xEE\xB4\xA\xC0\0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\xC0\0 ARM32,VFPv2 + +[FCMPEScc] +vreg,vreg \x92\xEE\xB4\xA\xC0\1 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\xC0\1 ARM32,VFPv2 + +[FCMPZDcc] +vreg \x92\xEE\xB5\xA\x40\0 THUMB32,VFPv2 +vreg \x42\xE\xB5\xA\x40\0 ARM32,VFPv2 + +[FCMPZScc] +vreg \x92\xEE\xB5\xA\x40\1 THUMB32,VFPv2 +vreg \x42\xE\xB5\xA\x40\1 ARM32,VFPv2 + +[FCMPEZDcc] +vreg \x92\xEE\xB5\xA\xC0\0 THUMB32,VFPv2 +vreg \x42\xE\xB5\xA\xC0\0 ARM32,VFPv2 + +[FCMPEZScc] +vreg \x92\xEE\xB5\xA\xC0\1 THUMB32,VFPv2 +vreg \x42\xE\xB5\xA\xC0\1 ARM32,VFPv2 + +[FCPYDcc] +vreg,vreg \x43\xEE\xB0\xB\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB0\xB\x40 ARM32,VFPv2 + +[FCPYScc] +vreg,vreg \x43\xEE\xB0\xA\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB0\xA\x40 ARM32,VFPv2 + +[FCVTDScc] +vreg,vreg \x43\xEE\xB7\xA\xC0 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB7\xA\xC0 ARM32,VFPv2 + +[FCVTSDcc] +vreg,vreg \x43\xEE\xB7\xB\xC0 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB7\xB\xC0 ARM32,VFPv2 + +[FDIVDcc] +vreg,vreg,vreg \x92\xEE\x80\xA\x0\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x80\xA\x0\0 ARM32,VFPv2 + +[FDIVScc] +vreg,vreg,vreg \x92\xEE\x80\xA\x0\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x80\xA\x0\1 ARM32,VFPv2 + +[FLDDcc] +vreg,memam2 \x95\xED\x10\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x10\xA ARM32,VFPv2 + +[FLDMcc] +memam4,reglist \x94\xEC\x10\xA THUMB32,VFPv2 +reg32,reglist \x94\xEC\x10\xA THUMB32,VFPv2 +memam4,reglist \x44\xC\x10\xA ARM32,VFPv2 +reg32,reglist \x44\xC\x10\xA ARM32,VFPv2 + +[FLDScc] +vreg,memam2 \x95\xED\x10\xA THUMB32,VFPv2 +vreg,memam2 \x45\xD\x10\xA ARM32,VFPv2 + +[FMACDcc] +vreg,vreg,vreg \x92\xEE\x0\xA\x00\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x0\xA\x00\0 ARM32,VFPv2 + +[FMACScc] +vreg,vreg,vreg \x92\xEE\x0\xA\x00\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x0\xA\x00\1 ARM32,VFPv2 + +[FMDHRcc] + +[FMDLRcc] + +[FMRDHcc] + +[FMRDLcc] + +[FMRScc] +reg32,vreg \x90\xEE\x10\xA\x10 THUMB32,VFPv2 +reg32,vreg \x40\xE\x10\xA\x10 ARM32,VFPv2 + +[FMRXcc] +reg32,regf \x91\xEE\xF0\xA\x10 THUMB32,VFPv2 +regf,regf \x91\xEE\xF0\xA\x10 THUMB32,VFPv2 +reg32,regf \x41\xE\xF0\xA\x10 ARM32,VFPv2 +regf,regf \x41\xE\xF0\xA\x10 ARM32,VFPv2 + +[FMSCDcc] +vreg,vreg,vreg \x92\xEE\x10\xA\x00\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x00\0 ARM32,VFPv2 + +[FMSCScc] +vreg,vreg,vreg \x92\xEE\x10\xA\x00\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x00\1 ARM32,VFPv2 + +[FMSRcc] +vreg,reg32 \x90\xEE\x00\xA\x10 THUMB32,VFPv2 +vreg,reg32 \x40\xE\x00\xA\x10 ARM32,VFPv2 + +[FMSTATcc] +void \x80\xEE\xF1\xFA\x10 THUMB32,VFPv2 +void \x2F\xE\xF1\xFA\x10 ARM32,VFPv2 + +[FMULDcc] +vreg,vreg,vreg \x92\xEE\x20\xA\x0\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x0\0 ARM32,VFPv2 + +[FMULScc] +vreg,vreg,vreg \x92\xEE\x20\xA\x0\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x0\1 ARM32,VFPv2 + +[FMXRcc] +regf,reg32 \x91\xEE\xE0\xA\x10 THUMB32,VFPv2 +regf,reg32 \x41\xE\xE0\xA\x10 ARM32,VFPv2 + +[FNEGDcc] +vreg,vreg \x92\xEE\xB1\xA\x40\0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\x40\0 ARM32,VFPv2 + +[FNEGScc] +vreg,vreg \x92\xEE\xB1\xA\x40\1 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\x40\1 ARM32,VFPv2 + +[FNMACDcc] +vreg,vreg,vreg \x92\xEE\x00\xA\x40\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x00\xA\x40\0 ARM32,VFPv2 + +[FNMACScc] +vreg,vreg,vreg \x92\xEE\x00\xA\x40\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x00\xA\x40\1 ARM32,VFPv2 + +[FNMSCDcc] +vreg,vreg,vreg \x92\xEE\x10\xA\x40\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x40\0 ARM32,VFPv2 + +[FNMSCScc] +vreg,vreg,vreg \x92\xEE\x10\xA\x40\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x40\1 ARM32,VFPv2 + +[FNMULDcc] +vreg,vreg,vreg \x92\xEE\x20\xA\x40\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x40\0 ARM32,VFPv2 + +[FNMULScc] +vreg,vreg,vreg \x92\xEE\x20\xA\x40\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x40\1 ARM32,VFPv2 + +[FSITODcc] +vreg,vreg \x43\xEE\xB8\xB\xC0 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB8\xB\xC0 ARM32,VFPv2 + +[FSITOScc] +vreg,vreg \x43\xEE\xB8\xA\xC0 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB8\xA\xC0 ARM32,VFPv2 + +[FSQRTDcc] +vreg,vreg \x92\xEE\xB1\xA\xC0\0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\xC0\0 ARM32,VFPv2 + +[FSQRTScc] +vreg,vreg \x92\xEE\xB1\xA\xC0\1 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\xC0\1 ARM32,VFPv2 + +[FSUBDcc] +vreg,vreg,vreg \x92\xEE\x30\xA\x40\0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x40\0 ARM32,VFPv2 + +[FSUBScc] +vreg,vreg,vreg \x92\xEE\x30\xA\x40\1 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x40\1 ARM32,VFPv2 + +[FTOSIDcc] +vreg,vreg \x43\xEE\xBD\xB\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xBD\xB\x40 ARM32,VFPv2 + +[FTOSIScc] +vreg,vreg \x43\xEE\xBD\xA\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xBD\xA\x40 ARM32,VFPv2 + +[FTOUIDcc] +vreg,vreg \x43\xEE\xBC\xB\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xBC\xB\x40 ARM32,VFPv2 + +[FTOUIScc] +vreg,vreg \x43\xEE\xBC\xA\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xBC\xA\x40 ARM32,VFPv2 + +[FUITODcc] +vreg,vreg \x43\xEE\xB8\xB\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB8\xB\x40 ARM32,VFPv2 + +[FUITOScc] +vreg,vreg \x43\xEE\xB8\xA\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB8\xA\x40 ARM32,VFPv2 + +[FMDRRcc] + +[FMRRDcc] ; Thumb-2 [POP] +reglist \x69\xBC THUMB,ARMv4T +reglist \x26\x8B ARM32,ARMv4 [PUSH] +reglist \x69\xB4 THUMB,ARMv4T +reglist \x26\x80 ARM32,ARMv4 [SDIVcc] +reg32,reg32,reg32 \x80\xFB\x90\xF0\xF0 THUMB32,ARMv7R,ARMv7M +reg32,reg32,reg32 \x15\x07\x10\x01\xF ARM32,ARMv7 [UDIVcc] +reg32,reg32,reg32 \x80\xFB\xB0\xF0\xF0 THUMB32,ARMv7R,ARMv7M +reg32,reg32,reg32 \x15\x07\x30\x01\xF ARM32,ARMv7 [MOVTcc] +reg32,imm \x81\xF2\xC0\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter \x81\xF2\xC0\x0\x0 THUMB32,ARMv6T2 + +reg32,imm \x2C\x3\x40 ARM32,ARMv6T2 +reg32,immshifter \x2C\x3\x40 ARM32,ARMv6T2 [IT] +condition \x6A\xBF\x08\x00 THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITE] +condition \x6A\xBF\x04\x88 THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITT] +condition \x6A\xBF\x04\x08 THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITEE] +condition \x6A\xBF\x02\xCC THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTE] +condition \x6A\xBF\x02\x4C THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITET] +condition \x6A\xBF\x02\x8C THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTT] +condition \x6A\xBF\x02\x0C THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITEEE] +condition \x6A\xBF\x01\xEE THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTEE] +condition \x6A\xBF\x01\x6E THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITETE] +condition \x6A\xBF\x01\xAE THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTTE] +condition \x6A\xBF\x01\x2E THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITEET] +condition \x6A\xBF\x01\xCE THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTET] +condition \x6A\xBF\x01\x4E THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITETT] +condition \x6A\xBF\x01\x8E THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 [ITTTT] +condition \x6A\xBF\x01\x0E THUMB,ARMv6T2 +condition \xFE ARM32,ARMv4 + +[TBBcc] +memam2 \x8E\xE8\xD0\xF0\x00 THUMB32,ARMv6T2 -[TBB] -[TBH] +[TBHcc] +memam2 \x8E\xE8\xD0\xF0\x10 THUMB32,ARMv6T2 [MOVW] +reg32,imm32 \x2C\x3\x0 ARM32,ARMv6T2 +reg32,immshifter \x2C\x3\x0 ARM32,ARMv6T2 + +reg32,imm32 \x81\xF2\x40\x0\x0 THUMB32,ARMv6T2 +reg32,immshifter \x81\xF2\x40\x0\x0 THUMB32,ARMv6T2 [CBZ] +reglo,immshifter \x68\xB1 THUMB,ARMv6T2 +reglo,memam2 \x68\xB1 THUMB,ARMv6T2 + [CBNZ] +reglo,immshifter \x68\xB9 THUMB,ARMv6T2 +reglo,memam2 \x68\xB9 THUMB,ARMv6T2 + +; VFP +[VABScc] +vreg,vreg \x92\xEE\xB0\xA\xC0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB0\xA\xC0 ARM32,VFPv2 + +[VADDcc] +vreg,vreg,vreg \x92\xEE\x30\xA\x0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x0 ARM32,VFPv2 + +[VCMPcc] +vreg,vreg \x92\xEE\xB4\xA\x40 THUMB32,VFPv2 +vreg,immshifter \x92\xEE\xB5\xA\x40 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\x40 ARM32,VFPv2 +vreg,immshifter \x42\xE\xB5\xA\x40 ARM32,VFPv2 + +[VCMPEcc] +vreg,vreg \x92\xEE\xB4\xA\xC0 THUMB32,VFPv2 +vreg,immshifter \x92\xEE\xB5\xA\xC0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB4\xA\xC0 ARM32,VFPv2 +vreg,immshifter \x42\xE\xB5\xA\xC0 ARM32,VFPv2 + +[VCVTcc] +vreg,vreg \x93\xEE\xB8\xA\xC0 THUMB32,VFPv2 +vreg,vreg,immshifter \x93\xEE\xBA\xA\x40 THUMB32,VFPv3 +vreg,vreg \x43\xE\xB8\xA\xC0 ARM32,VFPv2 +vreg,vreg,immshifter \x43\xE\xBA\xA\x40 ARM32,VFPv3 + +[VCVTRcc] +vreg,vreg \x93\xEE\xB8\xA\x40 THUMB32,VFPv2 +vreg,vreg \x43\xE\xB8\xA\x40 ARM32,VFPv2 + +[VDIVcc] +vreg,vreg,vreg \x92\xEE\x80\xA\x0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x80\xA\x0 ARM32,VFPv2 + +[VMRScc] +reg32,regf \x91\xEE\xF0\xA\x10 THUMB32,VFPv2 +regf,regf \x91\xEE\xF0\xA\x10 THUMB32,VFPv2 +reg32,regf \x41\xE\xF0\xA\x10 ARM32,VFPv2 +regf,regf \x41\xE\xF0\xA\x10 ARM32,VFPv2 + +[VMSRcc] +regf,reg32 \x91\xEE\xE0\xA\x10 THUMB32,VFPv2 +regf,reg32 \x41\xE\xE0\xA\x10 ARM32,VFPv2 + +[VMLAcc] +vreg,vreg,vreg \x92\xEE\x0\xA\x00 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x0\xA\x00 ARM32,VFPv2 + +[VMLScc] +vreg,vreg,vreg \x92\xEE\x0\xA\x40 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x0\xA\x40 ARM32,VFPv2 + +[VMULcc] +vreg,vreg,vreg \x92\xEE\x20\xA\x0 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x0 ARM32,VFPv2 + +[VNMLAcc] +vreg,vreg,vreg \x92\xEE\x10\xA\x40 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x40 ARM32,VFPv2 + +[VNMLScc] +vreg,vreg,vreg \x92\xEE\x10\xA\x00 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x10\xA\x00 ARM32,VFPv2 + +[VNMULcc] +vreg,vreg,vreg \x92\xEE\x20\xA\x40 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x20\xA\x40 ARM32,VFPv2 -; FPv4-s16 - ARMv7M floating point -[VABS] -[VADD] -[VCMP] -[VCMPE] -[VCVT] -[VDIV] -[VLDM] -[VLDR] -[VMOV] -[VMRS] -[VMSR] -[VMUL] -[VMLA] -[VMLS] -[VNMLA] -[VNMLS] [VFMA] +vreg,vreg,vreg \x92\xEE\xA0\xA\x00 THUMB32,VFPv4 +vreg,vreg,vreg \x42\xE\xA0\xA\x00 ARM32,VFPv4 + [VFMS] +vreg,vreg,vreg \x92\xEE\xA0\xA\x40 THUMB32,VFPv4 +vreg,vreg,vreg \x42\xE\xA0\xA\x40 ARM32,VFPv4 + [VFNMA] +vreg,vreg,vreg \x92\xEE\x90\xA\x00 THUMB32,VFPv4 +vreg,vreg,vreg \x42\xE\x90\xA\x00 ARM32,VFPv4 + [VFNMS] -[VNEG] -[VNMUL] -[VPOP] -[VPUSH] +vreg,vreg,vreg \x92\xEE\x90\xA\x40 THUMB32,VFPv4 +vreg,vreg,vreg \x42\xE\x90\xA\x40 ARM32,VFPv4 + +[VNEGcc] +vreg,vreg \x92\xEE\xB1\xA\x40 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\x40 ARM32,VFPv2 + [VSQRT] -[VSTM] -[VSTR] +vreg,vreg \x92\xEE\xB1\xA\xC0 THUMB32,VFPv2 +vreg,vreg \x42\xE\xB1\xA\xC0 ARM32,VFPv2 + [VSUB] +vreg,vreg,vreg \x92\xEE\x30\xA\x40 THUMB32,VFPv2 +vreg,vreg,vreg \x42\xE\x30\xA\x40 ARM32,VFPv2 + +[DMBcc] +immshifter \x80\xF3\xBF\x8F\x50 THUMB32,ARMv7 +immshifter \x2E\xF5\x7F\xF0\x50 ARM32,ARMv7 + +[ISBcc] +immshifter \x80\xF3\xBF\x8F\x60 THUMB32,ARMv7 +immshifter \x2E\xF5\x7F\xF0\x60 ARM32,ARMv7 + +[DSBcc] +immshifter \x80\xF3\xBF\x8F\x40 THUMB32,ARMv7 +immshifter \x2E\xF5\x7F\xF0\x40 ARM32,ARMv7 + +[SMCcc] +immshifter \x2E\x01\x60\x00\x70 ARM32,ARMv7 +imm32 \x2E\x01\x60\x00\x70 ARM32,ARMv7 ; Thumb armv6-m (gcc) -[NEG] -[SVC] +[NEGcc] + +[SVCcc] +immshifter \x61\xDF\x0 THUMB,ARMv4T +imm32 \x61\xDF\x0 THUMB,ARMv4T + +immshifter \x2\x0F ARM32,ARMv4 +imm32 \x2\x0F ARM32,ARMv4 + +[BXJcc] +reg32 \x80\xF3\xC0\x8F\x0 THUMB32,ARMv6T2 +reg32 \x3\x01\x2F\xFF\x20 ARM32,ARMv5TEJ + +; Undefined mnemonic +[UDF] +immshifter \x61\xDE\x0 THUMB,ARMv4T +void void ARM32,ARMv4T + +; FPA + + +[TANcc] +fpureg,fpureg \xA1\1\x15 ARM32,FPA +fpureg,immshifter \xA1\1\x15 ARM32,FPA + +[SQTcc] +fpureg,fpureg \xA1\1\x9 ARM32,FPA +fpureg,immshifter \xA1\1\x9 ARM32,FPA + +[SUFcc] +fpureg,fpureg,fpureg \xA1\0\x4 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x4 ARM32,FPA + +[RSFcc] +fpureg,fpureg,fpureg \xA1\0\x6 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x6 ARM32,FPA + +[RNDcc] +fpureg,fpureg \xA1\1\x7 ARM32,FPA +fpureg,immshifter \xA1\1\x7 ARM32,FPA + +[POLcc] +fpureg,fpureg,fpureg \xA1\0\x18 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x18 ARM32,FPA + +[RDFcc] +fpureg,fpureg,fpureg \xA1\0\xA ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\xA ARM32,FPA + +[RFScc] +reg32 \xA2\xE\x3 ARM32,FPA + +[RFCcc] +reg32 \xA2\xE\x5 ARM32,FPA + +[WFCcc] +reg32 \xA2\xE\x4 ARM32,FPA + +[RMFcc] +fpureg,fpureg,fpureg \xA1\0\x10 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x10 ARM32,FPA +[RPWcc] +fpureg,fpureg,fpureg \xA1\0\xC ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\xC ARM32,FPA + +[MNFcc] +fpureg,fpureg \xA1\1\x3 ARM32,FPA +fpureg,immshifter \xA1\1\x3 ARM32,FPA + +[MUFcc] +fpureg,fpureg,fpureg \xA1\0\x2 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x2 ARM32,FPA + +[ABScc] +fpureg,fpureg \xA1\1\x5 ARM32,FPA +fpureg,immshifter \xA1\1\x5 ARM32,FPA + +[ACScc] +fpureg,fpureg \xA1\1\x19 ARM32,FPA +fpureg,immshifter \xA1\1\x19 ARM32,FPA + +[ASNcc] +fpureg,fpureg \xA1\1\x17 ARM32,FPA +fpureg,immshifter \xA1\1\x17 ARM32,FPA + +[ATNcc] +fpureg,fpureg \xA1\1\x1B ARM32,FPA +fpureg,immshifter \xA1\1\x1B ARM32,FPA + +[CNFcc] +fpureg,fpureg \xA2\xE\xB0 ARM32,FPA +fpureg,immshifter \xA2\xE\xB0 ARM32,FPA + +[CNFEcc] +fpureg,fpureg \xA2\xE\xF0 ARM32,FPA +fpureg,immshifter \xA2\xE\xF0 ARM32,FPA + +[COScc] +fpureg,fpureg \xA1\1\x13 ARM32,FPA +fpureg,immshifter \xA1\1\x13 ARM32,FPA + +[DVFcc] +fpureg,fpureg,fpureg \xA1\0\x8 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x8 ARM32,FPA + +[EXPcc] +fpureg,fpureg \xA1\1\xF ARM32,FPA +fpureg,immshifter \xA1\1\xF ARM32,FPA + +[FDVcc] +fpureg,fpureg,fpureg \xA1\0\x14 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x14 ARM32,FPA + +[FLTcc] +fpureg,reg32 \xA2\xE\x00 ARM32,FPA + +[FIXcc] +reg32,fpureg \xA2\xE\x10 ARM32,FPA + +[FMLcc] +fpureg,fpureg,fpureg \xA1\0\x12 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x12 ARM32,FPA + +[FRDcc] +fpureg,fpureg,fpureg \xA1\0\x16 ARM32,FPA +fpureg,fpureg,immshifter \xA1\0\x16 ARM32,FPA + +[LGNcc] +fpureg,fpureg \xA1\1\xD ARM32,FPA +fpureg,immshifter \xA1\1\xD ARM32,FPA + +[LOGcc] +fpureg,fpureg \xA1\1\xB ARM32,FPA +fpureg,immshifter \xA1\1\xB ARM32,FPA \ No newline at end of file diff --git a/fpcsrc/compiler/arm/armnop.inc b/fpcsrc/compiler/arm/armnop.inc index 75c52639..5fc78695 100644 --- a/fpcsrc/compiler/arm/armnop.inc +++ b/fpcsrc/compiler/arm/armnop.inc @@ -1,2 +1,2 @@ { don't edit, this file is generated from armins.dat } -105; +952; diff --git a/fpcsrc/compiler/arm/armop.inc b/fpcsrc/compiler/arm/armop.inc index c91c9c03..84aa9755 100644 --- a/fpcsrc/compiler/arm/armop.inc +++ b/fpcsrc/compiler/arm/armop.inc @@ -1,12 +1,9 @@ { don't edit, this file is generated from armins.dat } ( A_NONE, -A_ABS, -A_ACS, -A_ASN, -A_ATN, A_ADC, A_ADD, +A_ADDW, A_ADF, A_ADR, A_AND, @@ -17,24 +14,18 @@ A_BLX, A_BKPT, A_BX, A_CDP, -A_CMF, -A_CMFE, A_CMN, A_CMP, +A_CMF, +A_CMFE, +A_STF, +A_LDF, +A_LFM, A_CLZ, -A_CNF, -A_COS, A_CPS, A_CPSID, A_CPSIE, -A_DVF, A_EOR, -A_EXP, -A_FDV, -A_FLT, -A_FIX, -A_FML, -A_FRD, A_LDC, A_LDM, A_LDRBT, @@ -44,41 +35,32 @@ A_LDRH, A_LDRSB, A_LDRSH, A_LDRT, -A_LDF, -A_LFM, -A_LGN, -A_LOG, A_MCR, +A_MCR2, +A_MRC, +A_MRC2, +A_MCRR, +A_MCRR2, +A_MRRC, +A_MRRC2, A_MLA, A_MOV, -A_MRC, A_MRS, A_MSR, -A_MNF, -A_MUF, A_MUL, A_MVF, A_MVN, +A_VMOV, A_NOP, +A_ORN, A_ORR, -A_RDF, -A_RFS, -A_RFC, -A_RMF, -A_RPW, A_RSB, A_RSC, -A_RSF, -A_RND, -A_POL, A_SBC, A_SFM, A_SIN, A_SMLAL, A_SMULL, -A_SQT, -A_SUF, -A_STF, A_STM, A_STR, A_STRB, @@ -89,16 +71,14 @@ A_SUB, A_SWI, A_SWP, A_SWPB, -A_TAN, A_TEQ, A_TST, A_UMLAL, A_UMULL, A_WFS, A_LDRD, -A_MCRR, -A_MRRC, A_PLD, +A_PLDW, A_QADD, A_QDADD, A_QDSUB, @@ -113,6 +93,12 @@ A_SMLALTB, A_SMLALTT, A_SMLAWB, A_SMLAWT, +A_VLDM, +A_VSTM, +A_VPOP, +A_VPUSH, +A_VLDR, +A_VSTR, A_SMULBB, A_SMULBT, A_SMULTB, @@ -120,67 +106,13 @@ A_SMULTT, A_SMULWB, A_SMULWT, A_STRD, -A_FABSD, -A_FABSS, -A_FADDD, -A_FADDS, -A_FCMPD, -A_FCMPED, -A_FCMPES, -A_FCMPEZD, -A_FCMPEZS, -A_FCMPS, -A_FCMPZD, -A_FCMPZS, -A_FCPYD, -A_FCPYS, -A_FCVTDS, -A_FCVTSD, -A_FDIVD, -A_FDIVS, -A_FLDD, -A_FLDM, -A_FLDS, -A_FMACD, -A_FMACS, -A_FMDHR, -A_FMDLR, -A_FMRDH, -A_FMRDL, -A_FMRS, -A_FMRX, -A_FMSCD, -A_FMSCS, -A_FMSR, -A_FMSTAT, -A_FMULD, -A_FMULS, -A_FMXR, -A_FNEGD, -A_FNEGS, -A_FNMACD, -A_FNMACS, -A_FNMSCD, -A_FNMSCS, -A_FNMULD, -A_FNMULS, -A_FSITOD, -A_FSITOS, -A_FSQRTD, -A_FSQRTS, +A_LDRHT, +A_STRHT, +A_LDRSBT, +A_LDRSHT, A_FSTD, A_FSTM, A_FSTS, -A_FSUBD, -A_FSUBS, -A_FTOSID, -A_FTOSIS, -A_FTOUID, -A_FTOUIS, -A_FUITOD, -A_FUITOS, -A_FMDRR, -A_FMRRD, A_BFC, A_BFI, A_CLREX, @@ -188,8 +120,13 @@ A_LDREX, A_LDREXB, A_LDREXD, A_LDREXH, +A_STREX, +A_STREXB, +A_STREXD, +A_STREXH, A_MLS, -A_PKH, +A_PKHBT, +A_PKHTB, A_PLI, A_QADD16, A_QADD8, @@ -212,6 +149,8 @@ A_ASR, A_LSR, A_LSL, A_ROR, +A_RRX, +A_UMAAL, A_SHADD16, A_SHADD8, A_SHASX, @@ -233,49 +172,102 @@ A_SSAT16, A_SSAX, A_SSUB16, A_SSUB8, -A_STREX, -A_STREXB, -A_STREXD, -A_STREXH, A_SXTAB, A_SXTAB16, A_SXTAH, +A_UBFX, +A_UXTAB, +A_UXTAB16, +A_UXTAH, A_SXTB, A_SXTB16, +A_SXTH, A_UXTB, +A_UXTB16, A_UXTH, -A_SXTH, A_UADD16, A_UADD8, A_UASX, -A_UBFX, A_UHADD16, A_UHADD8, A_UHASX, A_UHSAX, A_UHSUB16, A_UHSUB8, -A_UMAAL, A_UQADD16, A_UQADD8, A_UQASX, A_UQSAX, A_UQSUB16, A_UQSUB8, -A_UQSAD8, -A_UQSADA8, +A_USAD8, +A_USADA8, A_USAT, A_USAT16, A_USAX, A_USUB16, A_USUB8, -A_UXTAB, -A_UXTAB16, -A_UXTAH, -A_UXTB16, A_WFE, A_WFI, A_YIELD, +A_FABSD, +A_FABSS, +A_FADDD, +A_FADDS, +A_FCMPD, +A_FCMPS, +A_FCMPED, +A_FCMPES, +A_FCMPZD, +A_FCMPZS, +A_FCMPEZD, +A_FCMPEZS, +A_FCPYD, +A_FCPYS, +A_FCVTDS, +A_FCVTSD, +A_FDIVD, +A_FDIVS, +A_FLDD, +A_FLDM, +A_FLDS, +A_FMACD, +A_FMACS, +A_FMDHR, +A_FMDLR, +A_FMRDH, +A_FMRDL, +A_FMRS, +A_FMRX, +A_FMSCD, +A_FMSCS, +A_FMSR, +A_FMSTAT, +A_FMULD, +A_FMULS, +A_FMXR, +A_FNEGD, +A_FNEGS, +A_FNMACD, +A_FNMACS, +A_FNMSCD, +A_FNMSCS, +A_FNMULD, +A_FNMULS, +A_FSITOD, +A_FSITOS, +A_FSQRTD, +A_FSQRTS, +A_FSUBD, +A_FSUBS, +A_FTOSID, +A_FTOSIS, +A_FTOUID, +A_FTOUIS, +A_FUITOD, +A_FUITOS, +A_FMDRR, +A_FMRRD, A_POP, A_PUSH, A_SDIV, @@ -306,29 +298,59 @@ A_VADD, A_VCMP, A_VCMPE, A_VCVT, +A_VCVTR, A_VDIV, -A_VLDM, -A_VLDR, -A_VMOV, A_VMRS, A_VMSR, -A_VMUL, A_VMLA, A_VMLS, +A_VMUL, A_VNMLA, A_VNMLS, +A_VNMUL, A_VFMA, A_VFMS, A_VFNMA, A_VFNMS, A_VNEG, -A_VNMUL, -A_VPOP, -A_VPUSH, A_VSQRT, -A_VSTM, -A_VSTR, A_VSUB, +A_DMB, +A_ISB, +A_DSB, +A_SMC, A_NEG, -A_SVC +A_SVC, +A_BXJ, +A_UDF, +A_TAN, +A_SQT, +A_SUF, +A_RSF, +A_RND, +A_POL, +A_RDF, +A_RFS, +A_RFC, +A_WFC, +A_RMF, +A_RPW, +A_MNF, +A_MUF, +A_ABS, +A_ACS, +A_ASN, +A_ATN, +A_CNF, +A_CNFE, +A_COS, +A_DVF, +A_EXP, +A_FDV, +A_FLT, +A_FIX, +A_FML, +A_FRD, +A_LGN, +A_LOG ); diff --git a/fpcsrc/compiler/arm/armreg.dat b/fpcsrc/compiler/arm/armreg.dat index b7d264f1..87887d5d 100644 --- a/fpcsrc/compiler/arm/armreg.dat +++ b/fpcsrc/compiler/arm/armreg.dat @@ -87,7 +87,7 @@ S28,$04,$06,$0E,s28,0,0 S29,$04,$06,$2E,s29,0,0 D14,$04,$07,$0E,d14,0,0 S30,$04,$06,$0F,s30,0,0 -S31,$04,$06,$2F,s21,0,0 +S31,$04,$06,$2F,s31,0,0 D15,$04,$07,$0F,d15,0,0 D16,$04,$07,$10,d16,0,0 D17,$04,$07,$11,d17,0,0 @@ -145,4 +145,11 @@ BASEPRI,$05,$00,$1F,basepri,0,0 BASEPRI_MAX,$05,$00,$20,basepri_max,0,0 FAULTMASK,$05,$00,$21,faultmask,0,0 CONTROL,$05,$00,$22,control,0,0 - +; VFP registers +FPSID,$05,$00,$23,fpsid,0,0 +MVFR1,$05,$00,$24,mvfr1,0,0 +MVFR0,$05,$00,$25,mvfr0,0,0 +FPEXC,$05,$00,$26,fpexc,0,0 +APSR_nzcvq,$05,$00,$27,apsr_nzcvq,0,0 +APSR_g,$05,$00,$28,apsr_g,0,0 +APSR_nzcvqg,$05,$00,$29,apsr_nzcvqg,0,0 diff --git a/fpcsrc/compiler/arm/armtab.inc b/fpcsrc/compiler/arm/armtab.inc index f0e43f68..ad1beba1 100644 --- a/fpcsrc/compiler/arm/armtab.inc +++ b/fpcsrc/compiler/arm/armtab.inc @@ -3,736 +3,6665 @@ ( opcode : A_NONE; ops : 0; - optypes : (ot_none,ot_none,ot_none,ot_none); + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); code : #0; flags : if_none ), + ( + opcode : A_ADC; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#65#64; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADC; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ADC; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), ( opcode : A_ADC; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#160; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#241#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ADC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#235#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 ), ( opcode : A_ADC; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#160; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#235#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#160; + flags : if_arm32 or if_armv4 ), ( opcode : A_ADC; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); code : #6#0#160; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_ADC; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); code : #7#2#160; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #97#68#0; + flags : if_thumb or if_armv4t ), ( opcode : A_ADD; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#128; - flags : if_arm7 + optypes : (ot_reglo,ot_reglo,ot_reglo,ot_none,ot_none,ot_none); + code : #96#24#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #96#28#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #96#28#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #107#48#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reglo,ot_regsp,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #100#168#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_regsp,ot_regsp,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #100#176#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reg32,ot_regsp,ot_reg32,ot_none,ot_none,ot_none); + code : #100#68#104; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_regsp,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #100#68#133; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADD; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#241#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#235#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 ), ( opcode : A_ADD; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#128; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#235#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#128; + flags : if_arm32 or if_armv4 ), ( opcode : A_ADD; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); code : #6#0#128; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_ADD; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); code : #7#2#128; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ADDW; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #129#242#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ADF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_ADF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #103#160#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reglo,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #103#160#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none); + code : #129#242#175#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #129#242#175#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #129#242#175#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ADR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #51#2#15; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_AND; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#64#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_AND; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_AND; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 ), ( opcode : A_AND; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#0; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_AND; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#240#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_AND; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 ), ( opcode : A_AND; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#0; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_AND; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#0; + flags : if_arm32 or if_armv4 ), ( opcode : A_AND; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); code : #6#0#0; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_AND; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); code : #7#2#0; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #98#224#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #98#224#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #98#224#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #99#208#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #99#208#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_B; + ops : 1; + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #99#208#0; + flags : if_thumb or if_armv4t ), ( opcode : A_B; ops : 1; - optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none); + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); code : #1#10; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_B; ops : 1; - optypes : (ot_immediate24,ot_none,ot_none,ot_none); + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); code : #1#10; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BIC; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#67#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_BIC; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#32#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BIC; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#32#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_BIC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#32#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_BIC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#240#32#0#0; + flags : if_thumb32 or if_armv6t2 ), ( opcode : A_BIC; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#1#192; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#32#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 ), ( opcode : A_BIC; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#1#192; - flags : if_arm7 + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#32#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_BIC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #6#1#192; + flags : if_arm32 or if_armv4 ), ( opcode : A_BIC; ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); code : #6#1#192; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_BIC; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); code : #7#3#192; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BL; + ops : 1; + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#208; + flags : if_thumb or if_thumb32 or if_armv4t + ), + ( + opcode : A_BL; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#208; + flags : if_thumb or if_thumb32 or if_armv4t + ), + ( + opcode : A_BL; + ops : 1; + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#208; + flags : if_thumb or if_thumb32 or if_armv4t ), ( opcode : A_BL; ops : 1; - optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none); + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); code : #1#11; - flags : if_arm7 + flags : if_arm32 or if_armv4 ), ( opcode : A_BL; ops : 1; - optypes : (ot_immediate24,ot_none,ot_none,ot_none); + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); code : #1#11; - flags : if_arm7 + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #98#71#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#192; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#192; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #141#240#192; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_immediate24,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #40#250; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #40#250; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_BLX; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #3#1#47#255#48; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_BKPT; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #96#190#0; + flags : if_thumb or if_armv5t + ), + ( + opcode : A_BKPT; + ops : 1; + optypes : (ot_immediate,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #49#1#32#112; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_BKPT; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #49#1#32#112; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_BX; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #98#71#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_BX; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #3#1#47#255#16; + flags : if_arm32 or if_armv4t + ), + ( + opcode : A_CDP; + ops : 2; + optypes : (ot_reg8,ot_reg8,ot_none,ot_none,ot_none,ot_none); + code : #192#1#16#65; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMN; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#66#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_CMN; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#16#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_CMN; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#16#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CMN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#16#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CMN; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #12#1#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #14#1#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMN; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #15#1#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#66#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #97#69#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #107#40#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#176#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#176#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CMP; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#176#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #12#1#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMP; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #14#1#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMP; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #15#3#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CMF; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #162#14#144; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_CMF; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #162#14#144; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_CMFE; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #162#14#192; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_CMFE; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #162#14#192; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_STF; + ops : 2; + optypes : (ot_fpureg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #160#12#0#1#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LDF; + ops : 2; + optypes : (ot_fpureg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #160#12#16#1#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LFM; + ops : 3; + optypes : (ot_fpureg,ot_immediate or ot_bits32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #160#12#16#2#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LFM; + ops : 3; + optypes : (ot_fpureg,ot_immediateshifter,ot_memoryam2,ot_none,ot_none,ot_none); + code : #160#12#16#2#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_CLZ; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#176#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_CLZ; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #50#1#111#15#16; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CPS; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #143#243#175#129#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_CPS; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #70#241#2#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_CPSID; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #108#182#112; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_CPSID; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #143#243#175#134#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CPSID; + ops : 2; + optypes : (ot_modeflags,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #143#243#175#135#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CPSID; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #70#241#12#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_CPSID; + ops : 2; + optypes : (ot_modeflags,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #70#241#14#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_CPSIE; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #108#182#96; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_CPSIE; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #143#243#175#132#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CPSIE; + ops : 2; + optypes : (ot_modeflags,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #143#243#175#133#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_CPSIE; + ops : 1; + optypes : (ot_modeflags,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #70#241#8#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_CPSIE; + ops : 2; + optypes : (ot_modeflags,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #70#241#10#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_EOR; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#64#64; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_EOR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#128#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#128#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#128#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#240#128#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#128#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#128#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_EOR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_EOR; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#0#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_EOR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #7#2#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDC; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #209#192#1#17#65; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #105#200; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_reglo,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #105#200; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #140#232#16#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #140#232#16#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #38#129; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #38#129; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#16#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#112; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRBT; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #23#4#112; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRB; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#92#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRB; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#120#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#16#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LDRB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#80; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#88#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#104#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reglo,ot_memoryam5,ot_none,ot_none,ot_none,ot_none); + code : #103#152#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reglo,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #103#72#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#80#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LDR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#16; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRH; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#90#0#1; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRH; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#136#0#1; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#48#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LDRH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #34#16#176; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSB; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#86#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRSB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#249#16#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRSB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #34#16#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #35#80#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none,ot_none); + code : #36#80#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #37#16#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSH; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#94#0#1; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LDRSH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#249#48#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRSH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #34#16#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#80#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#48; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MCR; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_none); + code : #28#14#0#1; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MCR; + ops : 6; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_immediateshifter); + code : #28#14#0#1; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MCR2; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_none); + code : #28#254#0#1; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_MCR2; + ops : 6; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_immediateshifter); + code : #28#254#0#1; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_MRC; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_none); + code : #28#14#16#1; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MRC; + ops : 6; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_immediateshifter); + code : #28#14#16#1; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MRC2; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_none); + code : #28#254#16#1; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_MRC2; + ops : 6; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_regf,ot_regf,ot_immediateshifter); + code : #28#254#16#1; + flags : if_arm32 or if_armv5t + ), + ( + opcode : A_MCRR; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_reg32,ot_regf,ot_none); + code : #29#12#64#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_MCRR2; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_reg32,ot_regf,ot_none); + code : #29#252#64#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_MRRC; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_reg32,ot_regf,ot_none); + code : #29#12#80#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_MRRC2; + ops : 5; + optypes : (ot_regf,ot_immediateshifter,ot_reg32,ot_reg32,ot_regf,ot_none); + code : #29#252#80#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_MLA; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MLA; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#0#32#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #97#70#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #107#32#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#79#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#79#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reg32,ot_shifterop,ot_none,ot_none,ot_none,ot_none); + code : #8#1#160; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MOV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #10#1#160; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MOV; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #11#1#160; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MRS; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #150#243#239#128#0; + flags : if_thumb32 or if_armv6 + ), + ( + opcode : A_MRS; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #16#1#15; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MSR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #150#243#128#128#0; + flags : if_thumb32 or if_armv6 + ), + ( + opcode : A_MSR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #18#1#32#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MSR; + ops : 2; + optypes : (ot_regf,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #19#3#32#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MSR; + ops : 2; + optypes : (ot_regs,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #19#3#32#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MUL; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #100#67#64; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MUL; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_reglo,ot_none,ot_none,ot_none); + code : #100#67#64; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MUL; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#251#0#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MUL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#0#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MUL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #20#0#0#144; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MVF; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#1; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_MVF; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#1; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_MVN; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#67#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_MVN; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#111#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MVN; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#111#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_MVN; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #8#1#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MVN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #10#1#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MVN; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #11#1#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #144#238#176#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #64#14#176#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_reg32,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #144#238#16#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_vreg,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #144#238#0#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_reg32,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #64#14#16#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 2; + optypes : (ot_vreg,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #64#14#0#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_vreg,ot_vreg,ot_none,ot_none); + code : #144#236#80#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 4; + optypes : (ot_vreg,ot_vreg,ot_reg32,ot_reg32,ot_none,ot_none); + code : #144#236#64#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_vreg,ot_vreg,ot_none,ot_none); + code : #64#12#80#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 4; + optypes : (ot_vreg,ot_vreg,ot_reg32,ot_reg32,ot_none,ot_none); + code : #64#12#64#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_vreg,ot_none,ot_none,ot_none); + code : #144#236#80#11#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 3; + optypes : (ot_vreg,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #144#236#64#11#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_vreg,ot_none,ot_none,ot_none); + code : #64#12#80#11#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMOV; + ops : 3; + optypes : (ot_vreg,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #64#12#64#11#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_NOP; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #97#191#0; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_NOP; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#3#32#240#0; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_NOP; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#225#160#0#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ORN; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORN; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#240#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORN; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORN; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#67#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ORR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#240#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#64#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ORR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#1#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ORR; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #5#1#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ORR; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#1#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ORR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #7#3#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediatezero,ot_none,ot_none,ot_none); + code : #107#66#64; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_RSB; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#192#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#241#192#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#235#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#235#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #6#0#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#0#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #7#0#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #5#0#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#0#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RSC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #7#2#224; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SBC; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#65#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SBC; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#96#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#96#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#241#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#235#96#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#235#96#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SBC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#192; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SBC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #5#0#192; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SBC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate,ot_none,ot_none); + code : #6#0#192; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SBC; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#0#192; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SBC; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #7#2#192; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SFM; + ops : 3; + optypes : (ot_fpureg,ot_immediate or ot_bits32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #160#12#0#2#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_SFM; + ops : 3; + optypes : (ot_fpureg,ot_immediateshifter,ot_memoryam2,ot_none,ot_none,ot_none); + code : #160#12#0#2#0; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_SIN; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#17; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_SIN; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#17; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_SMLAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#0#224#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SMULL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#128#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMULL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#0#192#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #105#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_reglo,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #105#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #140#232#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #140#232#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #38#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #38#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STR; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#80#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STR; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#96#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STR; + ops : 2; + optypes : (ot_reglo,ot_memoryam5,ot_none,ot_none,ot_none,ot_none); + code : #103#144#0#2; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#64#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_STR; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRB; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#84#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STRB; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#112#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STRB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#0#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_STRB; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#0#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STRBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRBT; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #23#4#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRH; + ops : 2; + optypes : (ot_reglo,ot_memoryam3,ot_none,ot_none,ot_none,ot_none); + code : #101#82#0#1; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STRH; + ops : 2; + optypes : (ot_reglo,ot_memoryam4,ot_none,ot_none,ot_none,ot_none); + code : #102#128#0#1; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_STRH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#32#0#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_STRH; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #34#0#176; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#64#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STRT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #23#4#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_regsp,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #100#176#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_regsp,ot_regsp,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #100#176#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #96#26#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_reglo,ot_none,ot_none,ot_none); + code : #96#26#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #96#30#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #96#30#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reglo,ot_immediate or ot_bits8,ot_none,ot_none,ot_none,ot_none); + code : #107#56#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #107#56#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#241#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#235#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#235#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #128#241#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#235#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#235#160#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #4#0#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #4#0#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #4#0#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SUB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #6#0#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SWP; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #39#16#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SWPB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #39#20#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TEQ; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#144#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_TEQ; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#144#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_TEQ; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#144#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_TEQ; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #12#1#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TEQ; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #13#1#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TEQ; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #14#1#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TEQ; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #15#3#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TST; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#66#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_TST; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #128#240#16#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_TST; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#16#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_TST; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #128#234#16#15#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_TST; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #12#1#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TST; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #13#1#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TST; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #14#1#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TST; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #15#3#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_UMLAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#224#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UMLAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#0#160#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_UMULL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#160#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UMULL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#0#128#9; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_WFS; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #162#14#2; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LDRD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #137#232#80#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #25#0#0#0#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_PLD; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #135#248#16#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_PLD; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #37#245#80#240#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_PLDW; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #135#248#48#240#0; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_PLDW; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #37#245#16#240#0; + flags : if_arm32 or if_armv7 + ), + ( + opcode : A_QADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #130#250#128#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #26#1#0#5; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_QDADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #130#250#128#240#144; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QDADD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #26#1#64#5; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_QDSUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #130#250#128#240#176; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QDSUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #26#1#96#5; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_QSUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #130#250#128#240#160; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QSUB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #26#1#32#5; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLABB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#0#8; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLABT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#0#12; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLATB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#0#10; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLATT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#0#14; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLALBB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#1#64#8; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLALBT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#1#64#12; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLALTB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#1#64#10; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLALTT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#1#64#14; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLAWB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#48#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLAWB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#32#8; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMLAWT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#48#0#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLAWT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#1#32#12; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_VLDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VLDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VLDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VLDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VSTM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VSTM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VSTM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VSTM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VPOP; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #148#236#189#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VPOP; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #68#12#189#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VPUSH; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #148#237#45#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VPUSH; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #68#13#45#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VLDR; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VLDR; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VSTR; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VSTR; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_SMULBB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#1#96#8#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMULBT; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#1#96#12#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMULTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#1#96#10#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMULTT; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#1#96#14#0; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMULWB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #20#1#32#160; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_SMULWT; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #20#1#32#224; + flags : if_arm32 or if_armv5te + ), + ( + opcode : A_STRD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #137#232#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STRD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none); + code : #25#0#0#0#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#48#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #25#0#48#0#176; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STRHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#32#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STRHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#248#32#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STRHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #30#0#32#0#176; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#249#16#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRSBT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #30#0#48#0#208; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDRSHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #136#249#48#14#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDRSHT; + ops : 2; + optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #30#0#48#0#240; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_FSTD; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSTD; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSTM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSTM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSTM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSTM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSTS; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#0#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSTS; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#0#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_BFC; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #132#243#111#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BFC; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_immediate or ot_bits32,ot_none,ot_none,ot_none); + code : #132#243#111#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BFC; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #45#7#192#0#31; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BFC; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_immediate or ot_bits32,ot_none,ot_none,ot_none); + code : #45#7#192#0#31; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BFI; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #132#243#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BFI; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediate or ot_bits32,ot_none,ot_none); + code : #132#243#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BFI; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #45#7#192#0#16; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BFI; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediate or ot_bits32,ot_none,ot_none); + code : #45#7#192#0#16; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_CLREX; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#243#191#143#47; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_CLREX; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#245#127#240#31; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_LDREX; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #138#232#80#15#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_LDREX; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #24#1#144#15#159; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDREXB; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #138#232#208#15#79; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_LDREXB; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #24#1#208#15#159; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDREXD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #138#232#208#0#127; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_LDREXD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #24#1#176#15#159; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LDREXH; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #138#232#208#15#95; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_LDREXH; + ops : 2; + optypes : (ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none,ot_none); + code : #24#1#240#15#159; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STREX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #139#232#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_STREX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #24#1#128#15#144; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STREXB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #139#232#192#15#64; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_STREXB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #24#1#192#15#144; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STREXD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none); + code : #139#232#192#0#112; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_STREXD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none); + code : #24#1#160#15#144; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_STREXH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #139#232#192#15#80; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_STREXH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_memoryam6,ot_none,ot_none,ot_none); + code : #24#1#224#15#144; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_MLS; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#0#0#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MLS; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#0#96#9; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_PKHBT; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_PKHBT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_PKHBT; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#128#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_PKHBT; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#128#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_PKHTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#234#192#0#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_PKHTB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #128#234#192#0#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_PKHTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#128#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_PKHTB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#128#5; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_PLI; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #135#249#16#240#0; + flags : if_thumb32 or if_armv7 + ), + ( + opcode : A_PLI; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #37#244#80#240#0; + flags : if_arm32 or if_armv7 + ), + ( + opcode : A_QADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#144#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_QADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#128#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_QASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_QSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_QSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_QSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_QSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#32#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_RBIT; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#144#240#160; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RBIT; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #50#6#255#15#48; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_REV; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#186#0; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_REV; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#144#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_REV; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #50#6#191#15#48; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_REV16; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#186#64; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_REV16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#144#240#144; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_REV16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #50#6#191#15#176; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_REVSH; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#186#192; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_REVSH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#144#240#176; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_REVSH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #50#6#255#15#176; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#72#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#64#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#80#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SBFX; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #132#243#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SBFX; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #45#7#160#0#80; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_SEL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SEL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#128#251; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SETEND; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #43#241#1#0#0; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SEV; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #100#191#64; + flags : if_thumb or if_armv7 + ), + ( + opcode : A_SEV; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#3#32#240#4; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_ASR; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #96#1#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ASR; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #96#1#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ASR; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#65#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ASR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #130#234#79#0#32; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ASR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #130#234#79#0#32; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ASR; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#64#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ASR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#64#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ASR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #48#1#160#0#80; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ASR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #48#1#160#0#64; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LSR; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #96#8#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSR; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #96#8#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSR; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#64#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #130#234#79#0#16; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #130#234#79#0#16; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSR; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#32#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#32#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #48#1#160#0#48; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LSR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #48#1#160#0#32; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LSL; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #96#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSL; + ops : 3; + optypes : (ot_reglo,ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #96#0#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSL; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#64#128; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_LSL; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #130#234#79#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #130#234#79#0#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSL; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#96#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#96#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_LSL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #48#1#160#0#16; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_LSL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #48#1#160#0#0; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ROR; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #107#65#192; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_ROR; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #130#234#79#0#48; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ROR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #130#234#79#0#48; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ROR; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#250#96#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ROR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#96#240#0; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_ROR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #48#1#160#0#112; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ROR; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #48#1#160#0#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_RRX; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #128#234#79#0#48; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_RRX; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #48#1#160#0#96; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_UMAAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#224#0#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UMAAL; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#0#64#9; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#144#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#128#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SHSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#32; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SHSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#48#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMLAD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#32#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLAD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#7#0#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMLALD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#192#0#192; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLALD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#7#64#1; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SMLSD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLSD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#7#0#5; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMLSLD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #133#251#208#0#192; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMLSLD; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #22#7#64#5; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMMLA; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#80#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMMLA; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#7#80#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMMLS; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#96#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMMLS; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#7#80#13; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMMUL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#80#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMMUL; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#80#1#15; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMUAD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#32#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMUAD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#0#1#15; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SMUSD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#64#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SMUSD; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#0#5#15; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSAT; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #131#243#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSAT; + ops : 4; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #131#243#0#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSAT; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #42#6#160#0#16; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSAT; + ops : 4; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #42#6#160#0#16; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSAT16; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #131#243#32#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSAT16; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #42#6#160#15#48; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#16#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#64#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#64#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#160#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#160#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#32#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAB16; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#32#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#128#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAB16; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#128#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#0#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAH; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#0#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTAH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#176#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTAH; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#176#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UBFX; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #132#243#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UBFX; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_immediateshifter,ot_none,ot_none); + code : #45#7#224#0#80; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_UXTAB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#80#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#80#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#224#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTAB; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#224#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTAB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#48#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB16; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#48#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#64#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB16; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#64#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#192#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTAB16; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#192#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTAH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #134#250#16#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAH; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #134#250#16#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTAH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#240#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTAH; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #22#6#240#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTB; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#178#64; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_SXTB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#79#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SXTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#79#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SXTB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#175#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#175#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTB16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#47#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#47#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_SXTB16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#143#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#143#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTH; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#178#0; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_SXTH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#15#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SXTH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#15#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_SXTH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#191#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_SXTH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#191#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTB; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#178#192; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_UXTB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#95#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_UXTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#95#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_UXTB; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#239#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTB; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#239#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTB16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#63#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#63#240#128; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UXTB16; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#207#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#207#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTH; + ops : 2; + optypes : (ot_reglo,ot_reglo,ot_none,ot_none,ot_none,ot_none); + code : #97#178#128; + flags : if_thumb or if_armv6 + ), + ( + opcode : A_UXTH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #134#250#31#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_UXTH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #134#250#31#240#128; + flags : if_thumb32 or if_wide or if_armv6t2 + ), + ( + opcode : A_UXTH; + ops : 2; + optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #27#6#255#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UXTH; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none); + code : #27#6#255#7; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#144#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#128#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#144#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#128#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UHSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#96; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UHSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#112#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#144#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQADD16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#241; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#128#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQADD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#249; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#160#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQASX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#243; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQSAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQSUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_UQSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#80; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_UQSUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#96#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USAD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#112#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USAD8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#128#1#15; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USADA8; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #128#251#112#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USADA8; + ops : 4; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none); + code : #21#7#128#1; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USAT; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #131#243#128#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USAT; + ops : 4; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #131#243#128#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USAT; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #42#6#224#0#16; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USAT; + ops : 4; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_shifterop,ot_none,ot_none); + code : #42#6#224#0#16; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USAT16; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #131#243#160#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USAT16; + ops : 3; + optypes : (ot_reg32,ot_immediateshifter,ot_reg32,ot_none,ot_none,ot_none); + code : #42#6#224#15#48; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#224#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USAX; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#245; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#208#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USUB16; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#247; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_USUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#250#192#240#64; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_USUB8; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #22#6#80#255; + flags : if_arm32 or if_armv6 + ), + ( + opcode : A_WFE; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #100#191#32; + flags : if_thumb or if_armv7 + ), + ( + opcode : A_WFE; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#3#32#240#2; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_WFI; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #100#191#48; + flags : if_thumb or if_armv7 + ), + ( + opcode : A_WFI; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#3#32#240#3; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_YIELD; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #100#191#16; + flags : if_thumb or if_armv7 + ), + ( + opcode : A_YIELD; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#3#32#240#1; + flags : if_arm32 or if_armv6k + ), + ( + opcode : A_FABSD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#176#10#192#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FABSD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#176#10#192#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FABSS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#176#10#192#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FABSS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#176#10#192#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FADDD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#0#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FADDD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#0#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FADDS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#0#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FADDS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#0#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPED; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#192#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPED; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#192#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPES; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#192#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPES; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#192#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPZD; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPZD; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPZS; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPZS; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPEZD; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#192#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPEZD; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#192#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCMPEZS; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#192#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCMPEZS; + ops : 1; + optypes : (ot_vreg,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#192#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCPYD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#176#11#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCPYD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#176#11#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCPYS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#176#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCPYS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#176#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCVTDS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#183#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCVTDS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#183#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FCVTSD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#183#11#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FCVTSD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#183#11#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FDIVD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#128#10#0#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FDIVD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#128#10#0#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FDIVS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#128#10#0#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FDIVS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#128#10#0#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FLDD; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FLDD; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FLDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FLDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #148#236#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FLDM; + ops : 2; + optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FLDM; + ops : 2; + optypes : (ot_reg32,ot_reglist,ot_none,ot_none,ot_none,ot_none); + code : #68#12#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FLDS; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #149#237#16#10; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FLDS; + ops : 2; + optypes : (ot_vreg,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #69#13#16#10; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMACD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#0#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMACD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#0#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMACS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#0#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMACS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#0#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMRS; + ops : 2; + optypes : (ot_reg32,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #144#238#16#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMRS; + ops : 2; + optypes : (ot_reg32,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #64#14#16#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMRX; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #145#238#240#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMRX; + ops : 2; + optypes : (ot_regf,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #145#238#240#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMRX; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #65#14#240#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMRX; + ops : 2; + optypes : (ot_regf,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #65#14#240#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMSCD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#0#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMSCD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#0#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMSCS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#0#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMSCS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#0#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMSR; + ops : 2; + optypes : (ot_vreg,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #144#238#0#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMSR; + ops : 2; + optypes : (ot_vreg,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #64#14#0#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMSTAT; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#238#241#250#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMSTAT; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #47#14#241#250#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMULD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#0#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMULD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#0#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMULS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#0#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMULS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#0#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FMXR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #145#238#224#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FMXR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #65#14#224#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNEGD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNEGD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNEGS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNEGS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMACD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMACD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMACS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMACS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMSCD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMSCD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMSCS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMSCS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMULD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMULD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FNMULS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FNMULS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSITOD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#184#11#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSITOD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#11#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSITOS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#184#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSITOS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSQRTD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#192#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSQRTD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#192#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSQRTS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#192#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSQRTS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#192#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSUBD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#64#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSUBD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#64#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FSUBS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#64#1; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FSUBS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#64#1; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FTOSID; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#189#11#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FTOSID; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#189#11#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FTOSIS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#189#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FTOSIS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#189#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FTOUID; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#188#11#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FTOUID; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#188#11#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FTOUIS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#188#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FTOUIS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#188#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FUITOD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#184#11#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FUITOD; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#11#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_FUITOS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#238#184#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_FUITOS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_POP; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #105#188; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_POP; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #38#139; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_PUSH; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #105#180; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_PUSH; + ops : 1; + optypes : (ot_reglist,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #38#128; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SDIV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#144#240#240; + flags : if_thumb32 or if_armv7r or if_armv7m + ), + ( + opcode : A_SDIV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#16#1#15; + flags : if_arm32 or if_armv7 + ), + ( + opcode : A_UDIV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #128#251#176#240#240; + flags : if_thumb32 or if_armv7r or if_armv7m + ), + ( + opcode : A_UDIV; + ops : 3; + optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none); + code : #21#7#48#1#15; + flags : if_arm32 or if_armv7 + ), + ( + opcode : A_MOVT; + ops : 2; + optypes : (ot_reg32,ot_immediate,ot_none,ot_none,ot_none,ot_none); + code : #129#242#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MOVT; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #129#242#192#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MOVT; + ops : 2; + optypes : (ot_reg32,ot_immediate,ot_none,ot_none,ot_none,ot_none); + code : #44#3#64; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_MOVT; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #44#3#64; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_IT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#8#0; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_IT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#4#136; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#4#8; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#2#204; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#2#76; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#2#140; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#2#12; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITEEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#238; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITEEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#110; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTEE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITETE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#174; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITETE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTTE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#46; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTTE; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITEET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#206; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITEET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#78; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTET; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITETT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#142; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITETT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_ITTTT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #106#191#1#14; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_ITTTT; + ops : 1; + optypes : (ot_condition,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #254; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_TBB; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #142#232#208#240#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_TBH; + ops : 1; + optypes : (ot_memoryam2,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #142#232#208#240#16; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MOVW; + ops : 2; + optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none); + code : #44#3#0; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_MOVW; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #44#3#0; + flags : if_arm32 or if_armv6t2 + ), + ( + opcode : A_MOVW; + ops : 2; + optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none); + code : #129#242#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_MOVW; + ops : 2; + optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #129#242#64#0#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_CBZ; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #104#177; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_CBZ; + ops : 2; + optypes : (ot_reglo,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #104#177; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_CBNZ; + ops : 2; + optypes : (ot_reglo,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #104#185; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_CBNZ; + ops : 2; + optypes : (ot_reglo,ot_memoryam2,ot_none,ot_none,ot_none,ot_none); + code : #104#185; + flags : if_thumb or if_armv6t2 + ), + ( + opcode : A_VABS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#176#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VABS; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#176#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VADD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VADD; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCMP; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCMP; + ops : 2; + optypes : (ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCMP; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCMP; + ops : 2; + optypes : (ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCMPE; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#180#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCMPE; + ops : 2; + optypes : (ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #146#238#181#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCMPE; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#180#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCMPE; + ops : 2; + optypes : (ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #66#14#181#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCVT; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #147#238#184#10#192; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCVT; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #147#238#186#10#64; + flags : if_thumb32 or if_vfpv3 + ), + ( + opcode : A_VCVT; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#10#192; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VCVT; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #67#14#186#10#64; + flags : if_arm32 or if_vfpv3 + ), + ( + opcode : A_VCVTR; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #147#238#184#10#64; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VCVTR; + ops : 2; + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #67#14#184#10#64; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VDIV; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#128#10#0; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VDIV; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#128#10#0; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMRS; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #145#238#240#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMRS; + ops : 2; + optypes : (ot_regf,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #145#238#240#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMRS; + ops : 2; + optypes : (ot_reg32,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #65#14#240#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMRS; + ops : 2; + optypes : (ot_regf,ot_regf,ot_none,ot_none,ot_none,ot_none); + code : #65#14#240#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMSR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #145#238#224#10#16; + flags : if_thumb32 or if_vfpv2 + ), + ( + opcode : A_VMSR; + ops : 2; + optypes : (ot_regf,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #65#14#224#10#16; + flags : if_arm32 or if_vfpv2 + ), + ( + opcode : A_VMLA; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#0; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_BLX; - ops : 1; - optypes : (ot_memory or ot_bits32,ot_none,ot_none,ot_none); - code : #15#15; - flags : if_arm7 + opcode : A_VMLA; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#0; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_BLX; - ops : 1; - optypes : (ot_immediate24,ot_none,ot_none,ot_none); - code : #15#15; - flags : if_arm7 + opcode : A_VMLS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#0#10#64; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_BX; - ops : 1; - optypes : (ot_reg32,ot_none,ot_none,ot_none); - code : #3#1#47#255#16; - flags : if_arm7 + opcode : A_VMLS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#0#10#64; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_CDP; - ops : 2; - optypes : (ot_reg8,ot_reg8,ot_none,ot_none); - code : #192#1#16#65; - flags : if_arm7 + opcode : A_VMUL; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#0; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_CMN; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #12#1#96; - flags : if_arm7 + opcode : A_VMUL; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#0; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_CMN; + opcode : A_VNMLA; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #13#1#96; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#64; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_CMN; + opcode : A_VNMLA; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #14#1#96; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#64; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_CMN; - ops : 2; - optypes : (ot_reg32,ot_immediate,ot_none,ot_none); - code : #15#3#96; - flags : if_arm7 + opcode : A_VNMLS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#16#10#0; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_CMP; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #12#1#64; - flags : if_arm7 + opcode : A_VNMLS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#16#10#0; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_CMP; + opcode : A_VNMUL; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #13#1#64; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#32#10#64; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_CMP; + opcode : A_VNMUL; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #14#1#64; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#32#10#64; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_CMP; - ops : 2; - optypes : (ot_reg32,ot_immediate,ot_none,ot_none); - code : #15#3#64; - flags : if_arm7 + opcode : A_VFMA; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#160#10#0; + flags : if_thumb32 or if_vfpv4 ), ( - opcode : A_CLZ; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #39#1#1; - flags : if_arm7 + opcode : A_VFMA; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#160#10#0; + flags : if_arm32 or if_vfpv4 ), ( - opcode : A_EOR; + opcode : A_VFMS; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#32; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#160#10#64; + flags : if_thumb32 or if_vfpv4 ), ( - opcode : A_EOR; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#32; - flags : if_arm7 + opcode : A_VFMS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#160#10#64; + flags : if_arm32 or if_vfpv4 ), ( - opcode : A_EOR; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); - code : #6#0#32; - flags : if_arm7 + opcode : A_VFNMA; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#144#10#0; + flags : if_thumb32 or if_vfpv4 ), ( - opcode : A_EOR; + opcode : A_VFNMA; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #7#2#32; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#144#10#0; + flags : if_arm32 or if_vfpv4 ), ( - opcode : A_LDC; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #209#192#1#17#65; - flags : if_arm7 + opcode : A_VFNMS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#144#10#64; + flags : if_thumb32 or if_vfpv4 ), ( - opcode : A_LDM; - ops : 2; - optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none); - code : #38#129; - flags : if_arm7 + opcode : A_VFNMS; + ops : 3; + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#144#10#64; + flags : if_arm32 or if_vfpv4 ), ( - opcode : A_LDRB; + opcode : A_VNEG; ops : 2; - optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none); - code : #23#7#16; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#64; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_LDR; + opcode : A_VNEG; ops : 2; - optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none); - code : #23#5#16; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#64; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_LDRH; + opcode : A_VSQRT; ops : 2; - optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none); - code : #34#80#176; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #146#238#177#10#192; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_LDRH; + opcode : A_VSQRT; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #35#80#176; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_none,ot_none,ot_none,ot_none); + code : #66#14#177#10#192; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_LDRH; + opcode : A_VSUB; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none); - code : #36#80#176; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #146#238#48#10#64; + flags : if_thumb32 or if_vfpv2 ), ( - opcode : A_LDRH; + opcode : A_VSUB; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #37#16#176; - flags : if_arm7 + optypes : (ot_vreg,ot_vreg,ot_vreg,ot_none,ot_none,ot_none); + code : #66#14#48#10#64; + flags : if_arm32 or if_vfpv2 ), ( - opcode : A_LDRSB; - ops : 2; - optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none); - code : #34#80#208; - flags : if_arm7 + opcode : A_DMB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#243#191#143#80; + flags : if_thumb32 or if_armv7 ), ( - opcode : A_LDRSB; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #35#80#208; - flags : if_arm7 + opcode : A_DMB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #46#245#127#240#80; + flags : if_arm32 or if_armv7 ), ( - opcode : A_LDRSB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none); - code : #36#80#208; - flags : if_arm7 + opcode : A_ISB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#243#191#143#96; + flags : if_thumb32 or if_armv7 ), ( - opcode : A_LDRSB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #37#16#208; - flags : if_arm7 + opcode : A_ISB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #46#245#127#240#96; + flags : if_arm32 or if_armv7 ), ( - opcode : A_LDRSH; - ops : 2; - optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none); - code : #34#80#240; - flags : if_arm7 + opcode : A_DSB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#243#191#143#64; + flags : if_thumb32 or if_armv7 ), ( - opcode : A_LDRSH; - ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #35#80#240; - flags : if_arm7 + opcode : A_DSB; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #46#245#127#240#64; + flags : if_arm32 or if_armv7 ), ( - opcode : A_LDRSH; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none); - code : #36#80#240; - flags : if_arm7 + opcode : A_SMC; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #46#1#96#0#112; + flags : if_arm32 or if_armv7 ), ( - opcode : A_LDRSH; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #37#16#240; - flags : if_arm7 + opcode : A_SMC; + ops : 1; + optypes : (ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #46#1#96#0#112; + flags : if_arm32 or if_armv7 ), ( - opcode : A_LFM; - ops : 3; - optypes : (ot_reg32,ot_immediate or ot_bits8,ot_fpureg,ot_none); - code : #240#2#1; - flags : if_fpa + opcode : A_SVC; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #97#223#0; + flags : if_thumb or if_armv4t ), ( - opcode : A_MLA; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #21#0#32#144; - flags : if_arm7 + opcode : A_SVC; + ops : 1; + optypes : (ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #97#223#0; + flags : if_thumb or if_armv4t ), ( - opcode : A_MRS; + opcode : A_SVC; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #2#15; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_SVC; + ops : 1; + optypes : (ot_immediate or ot_bits32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #2#15; + flags : if_arm32 or if_armv4 + ), + ( + opcode : A_BXJ; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #128#243#192#143#0; + flags : if_thumb32 or if_armv6t2 + ), + ( + opcode : A_BXJ; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #3#1#47#255#32; + flags : if_arm32 or if_armv5tej + ), + ( + opcode : A_UDF; + ops : 1; + optypes : (ot_immediateshifter,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #97#222#0; + flags : if_thumb or if_armv4t + ), + ( + opcode : A_UDF; + ops : 0; + optypes : (ot_none,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #0; + flags : if_arm32 or if_armv4t + ), + ( + opcode : A_TAN; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #16#1#15; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#21; + flags : if_arm32 or if_fpa ), ( - opcode : A_MSR; + opcode : A_TAN; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #17#1#41#240; - flags : if_arm7 + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#21; + flags : if_arm32 or if_fpa ), ( - opcode : A_MSR; + opcode : A_SQT; ops : 2; - optypes : (ot_regf,ot_reg32,ot_none,ot_none); - code : #18#1#40#240; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#9; + flags : if_arm32 or if_fpa ), ( - opcode : A_MSR; + opcode : A_SQT; ops : 2; - optypes : (ot_regf,ot_immediate,ot_none,ot_none); - code : #19#3#40#240; - flags : if_arm7 + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#9; + flags : if_arm32 or if_fpa ), ( - opcode : A_MUL; + opcode : A_SUF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #20#0#0#144; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#4; + flags : if_arm32 or if_fpa ), ( - opcode : A_MVF; - ops : 2; - optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none); - code : #242; - flags : if_fpa + opcode : A_SUF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#4; + flags : if_arm32 or if_fpa ), ( - opcode : A_MVF; - ops : 2; - optypes : (ot_fpureg,ot_immediatefpu,ot_none,ot_none); - code : #242; - flags : if_fpa + opcode : A_RSF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#6; + flags : if_arm32 or if_fpa ), ( - opcode : A_ORR; + opcode : A_RSF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#1#128; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#6; + flags : if_arm32 or if_fpa ), ( - opcode : A_ORR; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#1#128; - flags : if_arm7 + opcode : A_RND; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#7; + flags : if_arm32 or if_fpa ), ( - opcode : A_ORR; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); - code : #6#1#128; - flags : if_arm7 + opcode : A_RND; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#7; + flags : if_arm32 or if_fpa ), ( - opcode : A_ORR; + opcode : A_POL; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #7#3#128; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#24; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSB; + opcode : A_POL; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#96; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#24; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSB; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#96; - flags : if_arm7 + opcode : A_RDF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#10; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSB; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); - code : #6#0#96; - flags : if_arm7 + opcode : A_RDF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#10; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #7#2#96; - flags : if_arm7 + opcode : A_RFS; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #162#14#3; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSC; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#224; - flags : if_arm7 + opcode : A_RFC; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #162#14#5; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSC; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#224; - flags : if_arm7 + opcode : A_WFC; + ops : 1; + optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none); + code : #162#14#4; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSC; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); - code : #6#0#224; - flags : if_arm7 + opcode : A_RMF; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#16; + flags : if_arm32 or if_fpa ), ( - opcode : A_RSC; + opcode : A_RMF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #7#2#224; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#16; + flags : if_arm32 or if_fpa ), ( - opcode : A_SBC; + opcode : A_RPW; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#192; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#12; + flags : if_arm32 or if_fpa ), ( - opcode : A_SBC; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #5#0#192; - flags : if_arm7 + opcode : A_RPW; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#12; + flags : if_arm32 or if_fpa ), ( - opcode : A_SBC; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_immediate); - code : #6#0#192; - flags : if_arm7 + opcode : A_MNF; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#3; + flags : if_arm32 or if_fpa ), ( - opcode : A_SBC; + opcode : A_MNF; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#3; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_MUF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #7#2#192; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#2; + flags : if_arm32 or if_fpa ), ( - opcode : A_SFM; + opcode : A_MUF; ops : 3; - optypes : (ot_reg32,ot_immediate or ot_bits8,ot_fpureg,ot_none); - code : #240#2#0; - flags : if_fpa + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#2; + flags : if_arm32 or if_fpa ), ( - opcode : A_SMLAL; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #22#0#224#144; - flags : if_arm7 + opcode : A_ABS; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#5; + flags : if_arm32 or if_fpa ), ( - opcode : A_SMULL; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #22#0#192#144; - flags : if_arm7 + opcode : A_ABS; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#5; + flags : if_arm32 or if_fpa ), ( - opcode : A_STM; + opcode : A_ACS; ops : 2; - optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none); - code : #38#128; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#25; + flags : if_arm32 or if_fpa ), ( - opcode : A_STR; + opcode : A_ACS; ops : 2; - optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none); - code : #23#4#0; - flags : if_arm7 + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#25; + flags : if_arm32 or if_fpa ), ( - opcode : A_STRB; + opcode : A_ASN; ops : 2; - optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none); - code : #23#6#0; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#23; + flags : if_arm32 or if_fpa ), ( - opcode : A_STRH; + opcode : A_ASN; ops : 2; - optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none); - code : #34#64#176; - flags : if_arm7 + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#23; + flags : if_arm32 or if_fpa ), ( - opcode : A_STRH; + opcode : A_ATN; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #35#64#176; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#27; + flags : if_arm32 or if_fpa ), ( - opcode : A_STRH; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none); - code : #36#64#176; - flags : if_arm7 + opcode : A_ATN; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#27; + flags : if_arm32 or if_fpa ), ( - opcode : A_STRH; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #37#0#176; - flags : if_arm7 + opcode : A_CNF; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #162#14#176; + flags : if_arm32 or if_fpa ), ( - opcode : A_SUB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none); - code : #4#0#64; - flags : if_arm7 + opcode : A_CNF; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #162#14#176; + flags : if_arm32 or if_fpa ), ( - opcode : A_SUB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none); - code : #4#0#64; - flags : if_arm7 + opcode : A_CNFE; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #162#14#240; + flags : if_arm32 or if_fpa ), ( - opcode : A_SUB; - ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #4#0#64; - flags : if_arm7 + opcode : A_CNFE; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #162#14#240; + flags : if_arm32 or if_fpa ), ( - opcode : A_SWI; - ops : 1; - optypes : (ot_immediate,ot_none,ot_none,ot_none); - code : #2#15; - flags : if_arm7 + opcode : A_COS; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#19; + flags : if_arm32 or if_fpa ), ( - opcode : A_SWP; + opcode : A_COS; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#19; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_DVF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #39#1#144; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#8; + flags : if_arm32 or if_fpa ), ( - opcode : A_SWPB; + opcode : A_DVF; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #39#1#144; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#8; + flags : if_arm32 or if_fpa ), ( - opcode : A_TEQ; + opcode : A_EXP; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #12#1#32; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#15; + flags : if_arm32 or if_fpa ), ( - opcode : A_TEQ; + opcode : A_EXP; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#15; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_FDV; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #13#1#32; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#20; + flags : if_arm32 or if_fpa ), ( - opcode : A_TEQ; + opcode : A_FDV; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #14#1#32; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#20; + flags : if_arm32 or if_fpa ), ( - opcode : A_TEQ; + opcode : A_FLT; ops : 2; - optypes : (ot_reg32,ot_immediate,ot_none,ot_none); - code : #15#3#32; - flags : if_arm7 + optypes : (ot_fpureg,ot_reg32,ot_none,ot_none,ot_none,ot_none); + code : #162#14#0; + flags : if_arm32 or if_fpa ), ( - opcode : A_TST; + opcode : A_FIX; ops : 2; - optypes : (ot_reg32,ot_reg32,ot_none,ot_none); - code : #12#1#0; - flags : if_arm7 + optypes : (ot_reg32,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #162#14#16; + flags : if_arm32 or if_fpa ), ( - opcode : A_TST; + opcode : A_FML; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none); - code : #13#1#0; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#18; + flags : if_arm32 or if_fpa ), ( - opcode : A_TST; + opcode : A_FML; ops : 3; - optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none); - code : #14#1#0; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#18; + flags : if_arm32 or if_fpa ), ( - opcode : A_TST; + opcode : A_FRD; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none); + code : #161#0#22; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_FRD; + ops : 3; + optypes : (ot_fpureg,ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none); + code : #161#0#22; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LGN; ops : 2; - optypes : (ot_reg32,ot_immediate,ot_none,ot_none); - code : #15#3#0; - flags : if_arm7 + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#13; + flags : if_arm32 or if_fpa ), ( - opcode : A_UMLAL; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #22#0#160#144; - flags : if_arm7 + opcode : A_LGN; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#13; + flags : if_arm32 or if_fpa ), ( - opcode : A_UMULL; - ops : 4; - optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32); - code : #22#0#128#144; - flags : if_arm7 + opcode : A_LOG; + ops : 2; + optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none); + code : #161#1#11; + flags : if_arm32 or if_fpa + ), + ( + opcode : A_LOG; + ops : 2; + optypes : (ot_fpureg,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none); + code : #161#1#11; + flags : if_arm32 or if_fpa ) ); diff --git a/fpcsrc/compiler/arm/cgcpu.pas b/fpcsrc/compiler/arm/cgcpu.pas index 5ea2b39a..babaa17f 100644 --- a/fpcsrc/compiler/arm/cgcpu.pas +++ b/fpcsrc/compiler/arm/cgcpu.pas @@ -104,7 +104,7 @@ unit cgcpu; procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size : tcgsize;src,dst: tregister;shuffle : pmmshuffle); override; { Transform unsupported methods into Internal errors } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); override; { try to generate optimized 32 Bit multiplication, returns true if successful generated } function try_optimized_mul32_const_reg_reg(list: TAsmList; a: tcgint; src, dst: tregister) : boolean; @@ -1703,7 +1703,7 @@ unit cgcpu; end; - procedure tbasecgarm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); + procedure tbasecgarm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); begin if reverse then begin @@ -2032,11 +2032,11 @@ unit cgcpu; ref.index:=ref.base; ref.base:=NR_NO; { FSTMX is deprecated on ARMv6 and later } - if (current_settings.cputypereg) then @@ -3053,7 +3041,6 @@ unit cgcpu; intreg, tmpmmreg : tregister; reg64 : tregister64; - op : tasmop; begin if assigned(shuffle) and not(shufflescalar(shuffle)) then @@ -3105,15 +3092,7 @@ unit cgcpu; end else begin - case fromsize of - OS_F32: - op:=A_FSTS; - OS_F64: - op:=A_FSTD; - else - internalerror(2009112418); - end; - handle_load_store(list,op,PF_None,tmpmmreg,ref); + handle_load_store(list,A_VSTR,PF_None,tmpmmreg,ref); end; end; @@ -3129,7 +3108,7 @@ unit cgcpu; if assigned(shuffle) and not shufflescalar(shuffle) then internalerror(2009112516); - list.concat(taicpu.op_reg_reg(A_FMSR,mmreg,intreg)); + list.concat(taicpu.op_reg_reg(A_VMOV,mmreg,intreg)); end; @@ -3144,7 +3123,7 @@ unit cgcpu; if assigned(shuffle) and not shufflescalar(shuffle) then internalerror(2009112514); - list.concat(taicpu.op_reg_reg(A_FMRS,intreg,mmreg)); + list.concat(taicpu.op_reg_reg(A_VMOV,intreg,mmreg)); end; @@ -3166,9 +3145,9 @@ unit cgcpu; a_load_const_reg(list,OS_32,0,tmpreg); case size of OS_F32: - list.concat(taicpu.op_reg_reg(A_FMSR,dst,tmpreg)); + list.concat(taicpu.op_reg_reg(A_VMOV,dst,tmpreg)); OS_F64: - list.concat(taicpu.op_reg_reg_reg(A_FMDRR,dst,tmpreg,tmpreg)); + list.concat(taicpu.op_reg_reg_reg(A_VMOV,dst,tmpreg,tmpreg)); else internalerror(2009112908); end; @@ -3290,7 +3269,7 @@ unit cgcpu; Internalerror(200109191); if GenerateThumbCode or GenerateThumb2Code then - list.concat(tai_thumb_func.create); + list.concat(tai_directive.Create(asd_thumb_func,'')); make_global:=false; if (not current_module.is_unit) or @@ -3433,7 +3412,7 @@ unit cgcpu; conversions } if (mmsize<>OS_F64) then internalerror(2009112405); - list.concat(taicpu.op_reg_reg_reg(A_FMDRR,mmreg,intreg.reglo,intreg.reghi)); + list.concat(taicpu.op_reg_reg_reg(A_VMOV,mmreg,intreg.reglo,intreg.reghi)); end; @@ -3443,7 +3422,7 @@ unit cgcpu; conversions } if (mmsize<>OS_F64) then internalerror(2009112406); - list.concat(taicpu.op_reg_reg_reg(A_FMRRD,intreg.reglo,intreg.reghi,mmreg)); + list.concat(taicpu.op_reg_reg_reg(A_VMOV,intreg.reglo,intreg.reghi,mmreg)); end; @@ -4378,7 +4357,13 @@ unit cgcpu; rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBNONE, [RS_F0,RS_F1,RS_F2,RS_F3,RS_F4,RS_F5,RS_F6,RS_F7],first_fpu_imreg,[]); - if current_settings.fputype in [fpu_fpv4_s16,fpu_vfpv3_d16] then + if current_settings.fputype=fpu_vfpv3 then + rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD, + [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7, + RS_D16,RS_D17,RS_D18,RS_D19,RS_D20,RS_D21,RS_D22,RS_D23,RS_D24,RS_D25,RS_D26,RS_D27,RS_D28,RS_D29,RS_D30,RS_D31, + RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15 + ],first_mm_imreg,[]) + else if current_settings.fputype in [fpu_fpv4_s16,fpu_vfpv3_d16] then rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBFD, [RS_D0,RS_D1,RS_D2,RS_D3,RS_D4,RS_D5,RS_D6,RS_D7, RS_D8,RS_D9,RS_D10,RS_D11,RS_D12,RS_D13,RS_D14,RS_D15 @@ -5301,19 +5286,13 @@ unit cgcpu; procedure tthumb2cgarm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister; shuffle: pmmshuffle); begin - if fromsize=OS_F32 then - handle_load_store(list,A_VLDR,PF_F32,reg,ref) - else - handle_load_store(list,A_VLDR,PF_F64,reg,ref); + handle_load_store(list,A_VLDR,PF_None,reg,ref); end; procedure tthumb2cgarm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tcgsize; reg: tregister; const ref: treference; shuffle: pmmshuffle); begin - if fromsize=OS_F32 then - handle_load_store(list,A_VSTR,PF_F32,reg,ref) - else - handle_load_store(list,A_VSTR,PF_F64,reg,ref); + handle_load_store(list,A_VSTR,PF_None,reg,ref); end; diff --git a/fpcsrc/compiler/arm/cpubase.pas b/fpcsrc/compiler/arm/cpubase.pas index 3ebc5c2b..66fd7f1a 100644 --- a/fpcsrc/compiler/arm/cpubase.pas +++ b/fpcsrc/compiler/arm/cpubase.pas @@ -93,7 +93,7 @@ unit cpubase; first_mm_imreg = $30; { TODO: Calculate bsstart} - regnumber_count_bsstart = 64; + regnumber_count_bsstart = 128; regnumber_table : array[tregisterindex] of tregister = ( {$i rarmnum.inc} @@ -130,6 +130,10 @@ unit cpubase; PF_S, { floating point size } PF_D,PF_E,PF_P,PF_EP, + { exchange } + PF_X, + { rounding } + PF_R, { load/store } PF_B,PF_SB,PF_BT,PF_H,PF_SH,PF_T, { multiple load/store address modes } @@ -138,10 +142,18 @@ unit cpubase; PF_IAD,PF_DBD,PF_FDD,PF_EAD, PF_IAS,PF_DBS,PF_FDS,PF_EAS, PF_IAX,PF_DBX,PF_FDX,PF_EAX, - { FPv4 postfixes } - PF_32,PF_64,PF_F32,PF_F64, - PF_F32S32,PF_F32U32, - PF_S32F32,PF_U32F32 + { VFP postfixes } + PF_8,PF_16,PF_32,PF_64, + PF_I8,PF_I16,PF_I32,PF_I64, + PF_S8,PF_S16,PF_S32,PF_S64, + PF_U8,PF_U16,PF_U32,PF_U64, + PF_P8, // polynomial + PF_F32,PF_F64, + PF_F32F64,PF_F64F32, + PF_F32S16,PF_F32U16,PF_S16F32,PF_U16F32, + PF_F64S16,PF_F64U16,PF_S16F64,PF_U16F64, + PF_F32S32,PF_F32U32,PF_S32F32,PF_U32F32, + PF_F64S32,PF_F64U32,PF_S32F64,PF_U32F64 ); TOpPostfixes = set of TOpPostfix; @@ -157,14 +169,24 @@ unit cpubase; oppostfix2str : array[TOpPostfix] of string[8] = ('', 's', 'd','e','p','ep', + 'x', + 'r', 'b','sb','bt','h','sh','t', 'ia','ib','da','db','fd','fa','ed','ea', 'iad','dbd','fdd','ead', 'ias','dbs','fds','eas', 'iax','dbx','fdx','eax', - '.32','.64','.f32','.f64', - '.f32.s32','.f32.u32', - '.s32.f32','.u32.f32'); + '.8','.16','.32','.64', + '.i8','.i16','.i32','.i64', + '.s8','.s16','.s32','.s64', + '.u8','.u16','.u32','.u64', + '.p8', + '.f32','.f64', + '.f32.f64','.f64.f32', + '.f32.s16','.f32.u16','.s16.f32','.u16.f32', + '.f64.s16','.f64.u16','.s16.f64','.u16.f64', + '.f32.s32','.f32.u32','.s32.f32','.u32.f32', + '.f64.s32','.f64.u32','.s32.f64','.u32.f64'); roundingmode2str : array[TRoundingMode] of string[1] = ('', 'p','m','z'); @@ -569,7 +591,6 @@ unit cpubase; var t : aint; i : longint; - imm : byte; begin {Loading 0-255 is simple} if (d and $FF) = d then @@ -584,10 +605,20 @@ unit cpubase; ) then result:=true {Can an 8-bit value be shifted accordingly?} - else if is_shifter_const(d,imm) then - result:=true else - result:=false; + begin + result:=false; + for i:=1 to 31 do + begin + t:=RolDWord(d,i); + if ((t and $FF)=t) and + ((t and $80)=$80) then + begin + result:=true; + exit; + end; + end; + end; end; function is_continuous_mask(d : aint;var lsb, width: byte) : boolean; diff --git a/fpcsrc/compiler/arm/cpuelf.pas b/fpcsrc/compiler/arm/cpuelf.pas index c912955f..3226885b 100644 --- a/fpcsrc/compiler/arm/cpuelf.pas +++ b/fpcsrc/compiler/arm/cpuelf.pas @@ -325,8 +325,15 @@ implementation result:=R_ARM_ABS32; RELOC_RELATIVE: result:=R_ARM_REL32; + RELOC_RELATIVE_24: + result:=R_ARM_JUMP24; + RELOC_RELATIVE_24_THUMB: + result:=R_ARM_CALL; + RELOC_RELATIVE_CALL_THUMB: + result:=R_ARM_THM_CALL; else result:=0; + writeln(objrel.typ); InternalError(2012110602); end; end; @@ -666,9 +673,14 @@ implementation begin if (reltyp=R_ARM_CALL) then { change BL to BLX, dest bit 1 goes to instruction bit 24 } - address:=(address and $FE000000) or (((tmp-curloc) and 2) shl 23) or $10000000 + address:=(address and $FE000000) or (((tmp-curloc) and 2) shl 23) or $F0000000 else InternalError(2014092001); + end + else if (address and $FF000000)=$FA000000 then + begin + { Change BLX to BL } + address:=(address and $EA000000) or $01000000; end; tmp:=tmp-curloc; // TODO: check overflow @@ -902,6 +914,11 @@ implementation end; + function elf_arm_encodeflags: longword; + begin + result:=EF_ARM_EABI_VER5; + end; + {***************************************************************************** Initialize *****************************************************************************} @@ -924,9 +941,26 @@ implementation encodereloc: @elf_arm_encodeReloc; loadreloc: @elf_arm_loadReloc; loadsection: @elf_arm_loadSection; + encodeflags: @elf_arm_encodeflags; ); + as_arm_elf32_info : tasminfo = + ( + id : as_arm_elf32; + idtxt : 'ELF'; + asmbin : ''; + asmcmd : ''; + supported_targets : [system_arm_embedded,system_arm_darwin, + system_arm_linux,system_arm_gba, + system_arm_nds]; + flags : [af_outputbinary,af_smartlink_sections,af_supports_dwarf]; + labelprefix : '.L'; + comment : ''; + dollarsign: '$'; + ); + initialization + RegisterAssembler(as_arm_elf32_info,TElfAssembler); ElfTarget:=elf_target_arm; ElfExeOutputClass:=TElfExeOutputARM; diff --git a/fpcsrc/compiler/arm/cpuinfo.pas b/fpcsrc/compiler/arm/cpuinfo.pas index c0ed34be..043e5260 100644 --- a/fpcsrc/compiler/arm/cpuinfo.pas +++ b/fpcsrc/compiler/arm/cpuinfo.pas @@ -67,7 +67,8 @@ Type fpu_vfpv2, fpu_vfpv3, fpu_vfpv3_d16, - fpu_fpv4_s16 + fpu_fpv4_s16, + fpu_vfpv4 ); tcontrollertype = @@ -399,7 +400,8 @@ Const 'VFPV2', 'VFPV3', 'VFPV3_D16', - 'FPV4_S16' + 'FPV4_S16', + 'VFPV4' ); @@ -746,7 +748,7 @@ Const { cpu_armv3 } [], { cpu_armv4 } [CPUARM_HAS_UMULL], { cpu_armv4t } [CPUARM_HAS_BX,CPUARM_HAS_UMULL], - { cpu_armv5 } [CPUARM_HAS_BX,CPUARM_HAS_BLX,CPUARM_HAS_BLX_LABEL,CPUARM_HAS_CLZ,CPUARM_HAS_UMULL], + { cpu_armv5 } [CPUARM_HAS_CLZ,CPUARM_HAS_UMULL], { cpu_armv5t } [CPUARM_HAS_BX,CPUARM_HAS_BLX,CPUARM_HAS_BLX_LABEL,CPUARM_HAS_CLZ,CPUARM_HAS_UMULL], { cpu_armv5te } [CPUARM_HAS_BX,CPUARM_HAS_BLX,CPUARM_HAS_BLX_LABEL,CPUARM_HAS_CLZ,CPUARM_HAS_EDSP,CPUARM_HAS_UMULL], { cpu_armv5tej } [CPUARM_HAS_BX,CPUARM_HAS_BLX,CPUARM_HAS_BLX_LABEL,CPUARM_HAS_CLZ,CPUARM_HAS_EDSP,CPUARM_HAS_UMULL], diff --git a/fpcsrc/compiler/arm/narmadd.pas b/fpcsrc/compiler/arm/narmadd.pas index 4e26f717..0f1ee49c 100644 --- a/fpcsrc/compiler/arm/narmadd.pas +++ b/fpcsrc/compiler/arm/narmadd.pas @@ -162,6 +162,7 @@ interface var op : TAsmOp; singleprec: boolean; + pf: TOpPostfix; begin pass_left_right; if (nf_swapped in flags) then @@ -210,33 +211,25 @@ interface location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); singleprec:=tfloatdef(left.resultdef).floattype=s32real; + if singleprec then + pf:=PF_F32 + else + pf:=PF_F64; case nodetype of addn : - if singleprec then - op:=A_FADDS - else - op:=A_FADDD; + op:=A_VADD; muln : - if singleprec then - op:=A_FMULS - else - op:=A_FMULD; + op:=A_VMUL; subn : - if singleprec then - op:=A_FSUBS - else - op:=A_FSUBD; + op:=A_VSUB; slashn : - if singleprec then - op:=A_FDIVS - else - op:=A_FDIVD; + op:=A_VDIV; else internalerror(2009111401); end; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op, - location.register,left.location.register,right.location.register)); + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(op, + location.register,left.location.register,right.location.register),pf)); end; fpu_fpv4_s16: begin @@ -275,6 +268,7 @@ interface procedure tarmaddnode.second_cmpfloat; var op: TAsmOp; + pf: TOpPostfix; begin pass_left_right; if (nf_swapped in flags) then @@ -310,19 +304,20 @@ interface hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,left.resultdef,true); hlcg.location_force_mmregscalar(current_asmdata.CurrAsmList,right.location,right.resultdef,true); + if nodetype in [equaln,unequaln] then + op:=A_VCMP + else + op:=A_VCMPE; + if (tfloatdef(left.resultdef).floattype=s32real) then - if nodetype in [equaln,unequaln] then - op:=A_FCMPS - else - op:=A_FCMPES - else if nodetype in [equaln,unequaln] then - op:=A_FCMPD + pf:=PF_F32 else - op:=A_FCMPED; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, - left.location.register,right.location.register)); + pf:=PF_F64; + + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(op, + left.location.register,right.location.register), pf)); cg.a_reg_alloc(current_asmdata.CurrAsmList,NR_DEFAULTFLAGS); - current_asmdata.CurrAsmList.concat(taicpu.op_none(A_FMSTAT)); + current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_VMRS,NR_APSR_nzcv,NR_FPSCR)); location.resflags:=GetFpuResFlags; end; fpu_fpv4_s16: diff --git a/fpcsrc/compiler/arm/narmcnv.pas b/fpcsrc/compiler/arm/narmcnv.pas index ae7f743b..62dd2aad 100644 --- a/fpcsrc/compiler/arm/narmcnv.pas +++ b/fpcsrc/compiler/arm/narmcnv.pas @@ -170,9 +170,9 @@ implementation procedure tarmtypeconvnode.second_int_to_real; const - signedprec2vfpop: array[boolean,OS_F32..OS_F64] of tasmop = - ((A_FUITOS,A_FUITOD), - (A_FSITOS,A_FSITOD)); + signedprec2vfppf: array[boolean,OS_F32..OS_F64] of toppostfix = + ((PF_F32U32,PF_F64U32), + (PF_F32S32,PF_F64S32)); var instr : taicpu; href : treference; @@ -253,8 +253,9 @@ implementation location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size) else location.register:=left.location.register; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg( - signedprec2vfpop[signed,location.size],location.register,left.location.register)); + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VCVT, + location.register,left.location.register), + signedprec2vfppf[signed,location.size])); end; fpu_fpv4_s16: begin diff --git a/fpcsrc/compiler/arm/narminl.pas b/fpcsrc/compiler/arm/narminl.pas index 2ba1cf61..97979e17 100644 --- a/fpcsrc/compiler/arm/narminl.pas +++ b/fpcsrc/compiler/arm/narminl.pas @@ -234,7 +234,7 @@ implementation procedure tarminlinenode.second_abs_real; var singleprec: boolean; - op: TAsmOp; + pf: TOpPostfix; begin load_fpu_location(singleprec); case current_settings.fputype of @@ -247,10 +247,10 @@ implementation fpu_vfpv3_d16: begin if singleprec then - op:=A_FABSS + pf:=PF_F32 else - op:=A_FABSD; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register)); + pf:=PF_F64; + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register),pf)); end; fpu_fpv4_s16: current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg(A_VABS,location.register,left.location.register), PF_F32)); @@ -270,7 +270,7 @@ implementation procedure tarminlinenode.second_sqr_real; var singleprec: boolean; - op: TAsmOp; + pf: TOpPostfix; begin load_fpu_location(singleprec); case current_settings.fputype of @@ -283,10 +283,10 @@ implementation fpu_vfpv3_d16: begin if singleprec then - op:=A_FMULS + pf:=PF_F32 else - op:=A_FMULD; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg_reg(op,location.register,left.location.register,left.location.register)); + pf:=PF_F64; + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register),pf)); end; fpu_fpv4_s16: current_asmdata.CurrAsmList.Concat(setoppostfix(taicpu.op_reg_reg_reg(A_VMUL,location.register,left.location.register,left.location.register), PF_F32)); @@ -299,7 +299,7 @@ implementation procedure tarminlinenode.second_sqrt_real; var singleprec: boolean; - op: TAsmOp; + pf: TOpPostfix; begin load_fpu_location(singleprec); case current_settings.fputype of @@ -312,13 +312,13 @@ implementation fpu_vfpv3_d16: begin if singleprec then - op:=A_FSQRTS + pf:=PF_F32 else - op:=A_FSQRTD; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op,location.register,left.location.register)); + pf:=PF_F64; + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register),pf)); end; fpu_fpv4_s16: - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register)); + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VSQRT,location.register,left.location.register), PF_F32)); else internalerror(2009111402); end; diff --git a/fpcsrc/compiler/arm/narmmat.pas b/fpcsrc/compiler/arm/narmmat.pas index f9a6e922..3e2d5b94 100644 --- a/fpcsrc/compiler/arm/narmmat.pas +++ b/fpcsrc/compiler/arm/narmmat.pas @@ -411,6 +411,7 @@ implementation procedure tarmunaryminusnode.second_float; var op: tasmop; + pf: TOpPostfix; begin secondpass(left); case current_settings.fputype of @@ -432,12 +433,14 @@ implementation location:=left.location; if (left.location.loc=LOC_CMMREGISTER) then location.register:=cg.getmmregister(current_asmdata.CurrAsmList,location.size); - if (location.size=OS_F32) then - op:=A_FNEGS + + if (tfloatdef(left.resultdef).floattype=s32real) then + pf:=PF_F32 else - op:=A_FNEGD; - current_asmdata.CurrAsmList.concat(taicpu.op_reg_reg(op, - location.register,left.location.register)); + pf:=PF_F64; + + current_asmdata.CurrAsmList.concat(setoppostfix(taicpu.op_reg_reg(A_VNEG, + location.register,left.location.register), pf)); end; fpu_fpv4_s16: begin diff --git a/fpcsrc/compiler/arm/narmmem.pas b/fpcsrc/compiler/arm/narmmem.pas index cdda1641..e316074f 100644 --- a/fpcsrc/compiler/arm/narmmem.pas +++ b/fpcsrc/compiler/arm/narmmem.pas @@ -27,6 +27,7 @@ interface uses globtype, + symtype, cgbase,cpubase,nmem,ncgmem; type @@ -36,7 +37,7 @@ interface tarmvecnode = class(tcgvecnode) - procedure update_reference_reg_mul(maybe_const_reg: tregister; l: aint);override; + procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override; end; implementation @@ -70,7 +71,7 @@ implementation TARMVECNODE *****************************************************************************} - procedure tarmvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint); + procedure tarmvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); var hreg: tregister; hl : longint; @@ -79,7 +80,7 @@ implementation (GenerateThumbCode) or { simple constant? } (l=1) or ispowerof2(l,hl) or ispowerof2(l+1,hl) or ispowerof2(l-1,hl) then - inherited update_reference_reg_mul(maybe_const_reg,l) + inherited update_reference_reg_mul(maybe_const_reg,regsize,l) else if (location.reference.base<>NR_NO) then begin hreg:=cg.getaddressregister(current_asmdata.CurrAsmList); diff --git a/fpcsrc/compiler/arm/raarmgas.pas b/fpcsrc/compiler/arm/raarmgas.pas index e7de7b8d..07ffca3e 100644 --- a/fpcsrc/compiler/arm/raarmgas.pas +++ b/fpcsrc/compiler/arm/raarmgas.pas @@ -30,6 +30,7 @@ Unit raarmgas; cpubase; type + tarmattreader = class(tattreader) actoppostfix : TOpPostfix; actwideformat : boolean; @@ -45,6 +46,13 @@ Unit raarmgas; procedure ReadSym(oper : tarmoperand); procedure ConvertCalljmp(instr : tarminstruction); procedure HandleTargetDirective; override; + protected + function is_unified: boolean; virtual; + end; + + tarmunifiedattreader = class(tarmattreader) + protected + function is_unified: boolean; override; end; @@ -63,15 +71,21 @@ Unit raarmgas; cgbase,cgutils; + function tarmunifiedattreader.is_unified: boolean; + begin + result:=true; + end; + + function tarmattreader.is_register(const s:string):boolean; type treg2str = record - name : string[2]; + name : string[3]; reg : tregister; end; const - extraregs : array[0..19] of treg2str = ( + extraregs : array[0..19+16] of treg2str = ( (name: 'A1'; reg : NR_R0), (name: 'A2'; reg : NR_R1), (name: 'A3'; reg : NR_R2), @@ -91,7 +105,25 @@ Unit raarmgas; (name: 'IP'; reg : NR_R12), (name: 'SP'; reg : NR_R13), (name: 'LR'; reg : NR_R14), - (name: 'PC'; reg : NR_R15)); + (name: 'PC'; reg : NR_R15), + + (name: 'C0'; reg : NR_CR0), + (name: 'C1'; reg : NR_CR1), + (name: 'C2'; reg : NR_CR2), + (name: 'C3'; reg : NR_CR3), + (name: 'C4'; reg : NR_CR4), + (name: 'C5'; reg : NR_CR5), + (name: 'C6'; reg : NR_CR6), + (name: 'C7'; reg : NR_CR7), + (name: 'C8'; reg : NR_CR8), + (name: 'C9'; reg : NR_CR9), + (name: 'C10'; reg : NR_CR10), + (name: 'C11'; reg : NR_CR11), + (name: 'C12'; reg : NR_CR12), + (name: 'C13'; reg : NR_CR13), + (name: 'C14'; reg : NR_CR14), + (name: 'C15'; reg : NR_CR15) + ); var i : longint; @@ -101,7 +133,7 @@ Unit raarmgas; { reg found? possible aliases are always 2 char } - if result or (length(s)<>2) then + if result or (not (length(s) in [2,3])) then exit; for i:=low(extraregs) to high(extraregs) do begin @@ -241,7 +273,9 @@ Unit raarmgas; do_error; oper.opr.ref.shiftimm := shift; test_end(require_rbracket); - end; + end + else + test_end(require_rbracket); end else begin @@ -528,7 +562,7 @@ Unit raarmgas; else if (actasmpattern='ROR') then handlepara(SM_ROR) else if (actasmpattern='RRX') then - handlepara(SM_ROR) + handlepara(SM_RRX) else result:=false; end @@ -785,6 +819,18 @@ Unit raarmgas; end; + function getregsetindex(reg: tregister): integer; + begin + if getsubreg(reg)=R_SUBFS then + begin + result:=getsupreg(reg)*2; + if result>32 then + result:=result-63; + end + else + result:=getsupreg(reg); + end; + var tempreg : tregister; ireg : tsuperregister; @@ -958,7 +1004,7 @@ Unit raarmgas; oper.opr.typ:=OPR_REGISTER; oper.opr.reg:=tempreg; end - else if (actasmtoken=AS_NOT) and (actopcode in [A_LDM,A_STM,A_FLDM,A_FSTM]) then + else if (actasmtoken=AS_NOT) and (actopcode in [A_LDM,A_STM,A_FLDM,A_FSTM,A_VLDM,A_VSTM]) then begin consume(AS_NOT); oper.opr.typ:=OPR_REFERENCE; @@ -976,11 +1022,11 @@ Unit raarmgas; registerset:=[]; regtype:=R_INVALIDREGISTER; subreg:=R_SUBNONE; - while true do + while actasmtoken<>AS_RSBRACKET do begin if actasmtoken=AS_REGISTER then begin - include(registerset,getsupreg(actasmregister)); + include(registerset,getregsetindex(actasmregister)); if regtype<>R_INVALIDREGISTER then begin if (getregtype(actasmregister)<>regtype) or @@ -997,7 +1043,7 @@ Unit raarmgas; if actasmtoken=AS_MINUS then begin consume(AS_MINUS); - for ireg:=getsupreg(tempreg) to getsupreg(actasmregister) do + for ireg:=getregsetindex(tempreg) to getregsetindex(actasmregister) do include(registerset,ireg); consume(AS_REGISTER); end; @@ -1137,8 +1183,19 @@ Unit raarmgas; case actasmtoken of AS_COMMA: { Operand delimiter } Begin - if ((instr.opcode in [A_MOV, A_MVN, A_CMP, A_CMN, A_TST, A_TEQ]) and (operandnum=2)) or - ((operandnum=3) and not(instr.opcode in [A_UMLAL,A_UMULL,A_SMLAL,A_SMULL,A_MLA,A_MRC,A_MCR,A_MCRR,A_MRRC])) then + if ((instr.opcode in [A_MOV,A_MVN,A_CMP,A_CMN,A_TST,A_TEQ, + A_UXTB,A_UXTH,A_UXTB16, + A_SXTB,A_SXTH,A_SXTB16]) and + (operandnum=2)) or + ((operandnum=3) and not(instr.opcode in [A_UMLAL,A_UMULL,A_SMLAL,A_SMULL,A_MLA,A_UMAAL,A_MLS, + A_SMLABB,A_SMLABT,A_SMLATB,A_SMLATT,A_SMMLA,A_SMMLS,A_SMLAD,A_SMLALD,A_SMLSD, + A_SMLALBB,A_SMLALBT,A_SMLALTB,A_SMLALTT,A_SMLSLD, + A_SMLAWB,A_SMLAWT, + A_MRC,A_MCR,A_MCRR,A_MRRC,A_MRC2,A_MCR2,A_MCRR2,A_MRRC2, + A_STREXD,A_STRD, + A_USADA8, + A_VMOV, + A_SBFX,A_UBFX,A_BFI])) then begin Consume(AS_COMMA); if not(TryBuildShifterOp(instr.Operands[operandnum+1] as tarmoperand)) then @@ -1160,7 +1217,8 @@ Unit raarmgas; break; end; else - if (instr.opcode = A_MSR) and (operandnum = 1) then + if ((instr.opcode = A_MRS) and (operandnum = 2)) or + ((instr.opcode = A_MSR) and (operandnum = 1)) then BuildSpecialreg(instr.Operands[operandnum] as tarmoperand) else BuildOperand(instr.Operands[operandnum] as tarmoperand); @@ -1174,25 +1232,34 @@ Unit raarmgas; const { sorted by length so longer postfixes will match first } - postfix2strsorted : array[1..31] of string[3] = ( - 'IAD','DBD','FDD','EAD', - 'IAS','DBS','FDS','EAS', - 'IAX','DBX','FDX','EAX', - 'EP','SB','BT','SH', - 'IA','IB','DA','DB','FD','FA','ED','EA', - 'B','D','E','P','T','H','S'); - - postfixsorted : array[1..31] of TOpPostfix = ( - PF_IAD,PF_DBD,PF_FDD,PF_EAD, - PF_IAS,PF_DBS,PF_FDS,PF_EAS, - PF_IAX,PF_DBX,PF_FDX,PF_EAX, - PF_EP,PF_SB,PF_BT,PF_SH, - PF_IA,PF_IB,PF_DA,PF_DB,PF_FD,PF_FA,PF_ED,PF_EA, - PF_B,PF_D,PF_E,PF_P,PF_T,PF_H,PF_S); + postfix2strsorted : array[1..70] of string[9] = ( + '.F32.S32','.F32.U32','.S32.F32','.U32.F32','.F64.S32','.F64.U32','.S32.F64','.U32.F64', + '.F32.S16','.F32.U16','.S16.F32','.U16.F32','.F64.S16','.F64.U16','.S16.F64','.U16.F64', + '.F32.F64','.F64.F32', + '.I16','.I32','.I64','.S16','.S32','.S64','.U16','.U32','.U64','.F32','.F64', + 'IAD','DBD','FDD','EAD','IAS','DBS','FDS','EAS','IAX','DBX','FDX','EAX', + '.16','.32','.64','.I8','.S8','.U8','.P8', + 'EP','SB','BT','SH','IA','IB','DA','DB','FD','FA','ED','EA', + '.8','S','D','E','P','X','R','B','H','T'); + + postfixsorted : array[1..70] of TOpPostfix = ( + PF_F32S32,PF_F32U32,PF_S32F32,PF_U32F32,PF_F64S32,PF_F64U32,PF_S32F64,PF_U32F64, + PF_F32S16,PF_F32U16,PF_S16F32,PF_U16F32,PF_F64S16,PF_F64U16,PF_S16F64,PF_U16F64, + PF_F32F64,PF_F64F32, + PF_I16,PF_I32, + PF_I64,PF_S16,PF_S32,PF_S64,PF_U16,PF_U32,PF_U64,PF_F32, + PF_F64,PF_IAD,PF_DBD,PF_FDD,PF_EAD, + PF_IAS,PF_DBS,PF_FDS,PF_EAS,PF_IAX, + PF_DBX,PF_FDX,PF_EAX,PF_16,PF_32, + PF_64,PF_I8,PF_S8,PF_U8,PF_P8, + PF_EP,PF_SB,PF_BT,PF_SH,PF_IA, + PF_IB,PF_DA,PF_DB,PF_FD,PF_FA, + PF_ED,PF_EA,PF_8,PF_S,PF_D,PF_E, + PF_P,PF_X,PF_R,PF_B,PF_H,PF_T); var - j : longint; - hs : string; + j, j2 : longint; + hs,hs2 : string; maxlen : longint; icond : tasmcond; Begin @@ -1220,61 +1287,126 @@ Unit raarmgas; end; end; end; - maxlen:=max(length(hs),5); + maxlen:=min(length(hs),6); actopcode:=A_NONE; - for j:=maxlen downto 1 do + j2:=maxlen; + hs2:=hs; + while j2>=1 do begin - actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j)))); - if actopcode<>A_NONE then + hs:=hs2; + while j2>=1 do begin - actasmtoken:=AS_OPCODE; - { strip op code } - delete(hs,1,j); - break; + actopcode:=tasmop(PtrUInt(iasmops.Find(copy(hs,1,j2)))); + if actopcode<>A_NONE then + begin + actasmtoken:=AS_OPCODE; + { strip op code } + delete(hs,1,j2); + dec(j2); + break; + end; + dec(j2); end; - end; - if actopcode=A_NONE then - exit; - { search for condition, conditions are always 2 chars } - if length(hs)>1 then - begin - for icond:=low(tasmcond) to high(tasmcond) do + if actopcode=A_NONE then + exit; + + if is_unified then begin - if copy(hs,1,2)=uppercond2str[icond] then + { check for postfix } + if (length(hs)>0) and (actoppostfix=PF_None) then begin - actcondition:=icond; - { strip condition } - delete(hs,1,2); - break; + for j:=low(postfixsorted) to high(postfixsorted) do + begin + if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then + begin + if not ((length(hs)-length(postfix2strsorted[j])) in [0,2,4]) then + continue; + + actoppostfix:=postfixsorted[j]; + { strip postfix } + delete(hs,1,length(postfix2strsorted[j])); + break; + end; + end; end; - end; - end; - { check for postfix } - if length(hs)>0 then - begin - for j:=low(postfixsorted) to high(postfixsorted) do + { search for condition, conditions are always 2 chars } + if length(hs)>1 then + begin + for icond:=low(tasmcond) to high(tasmcond) do + begin + if copy(hs,1,2)=uppercond2str[icond] then + begin + actcondition:=icond; + { strip condition } + delete(hs,1,2); + break; + end; + end; + end; + { check for postfix } + if (length(hs)>0) and (actoppostfix=PF_None) then + begin + for j:=low(postfixsorted) to high(postfixsorted) do + begin + if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then + begin + if not ((length(hs)-length(postfix2strsorted[j])) = 0) then + continue; + + actoppostfix:=postfixsorted[j]; + { strip postfix } + delete(hs,1,length(postfix2strsorted[j])); + break; + end; + end; + end; + end + else begin - if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then + { search for condition, conditions are always 2 chars } + if length(hs)>1 then begin - actoppostfix:=postfixsorted[j]; - { strip postfix } - delete(hs,1,length(postfix2strsorted[j])); - break; + for icond:=low(tasmcond) to high(tasmcond) do + begin + if copy(hs,1,2)=uppercond2str[icond] then + begin + actcondition:=icond; + { strip condition } + delete(hs,1,2); + break; + end; + end; + end; + { check for postfix } + if (length(hs)>0) and (actoppostfix=PF_None) then + begin + for j:=low(postfixsorted) to high(postfixsorted) do + begin + if copy(hs,1,length(postfix2strsorted[j]))=postfix2strsorted[j] then + begin + actoppostfix:=postfixsorted[j]; + { strip postfix } + delete(hs,1,length(postfix2strsorted[j])); + break; + end; + end; end; end; - end; - { check for format postfix } - if length(hs)>0 then - begin - if upcase(copy(hs,1,2)) = '.W' then + { check for format postfix } + if length(hs)>0 then begin - actwideformat:=true; - delete(hs,1,2); + if copy(hs,1,2) = '.W' then + begin + actwideformat:=true; + delete(hs,1,2); + end; end; + { if we stripped all postfixes, it's a valid opcode } + is_asmopcode:=length(hs)=0; + if is_asmopcode = true then + break; end; - { if we stripped all postfixes, it's a valid opcode } - is_asmopcode:=length(hs)=0; end; @@ -1313,12 +1445,17 @@ Unit raarmgas; else if actasmpattern='.thumb_func' then begin consume(AS_TARGET_DIRECTIVE); - curList.concat(tai_thumb_func.create); + curList.concat(tai_directive.create(asd_thumb_func,'')); end else inherited HandleTargetDirective; end; + function tarmattreader.is_unified: boolean; + begin + result:=false; + end; + procedure tarmattreader.handleopcode; var @@ -1348,10 +1485,17 @@ const asmmode_arm_att_info : tasmmodeinfo = ( id : asmmode_arm_gas; - idtxt : 'GAS'; + idtxt : 'DIVIDED'; casmreader : tarmattreader; ); + asmmode_arm_att_unified_info : tasmmodeinfo = + ( + id : asmmode_arm_gas_unified; + idtxt : 'UNIFIED'; + casmreader : tarmunifiedattreader; + ); + asmmode_arm_standard_info : tasmmodeinfo = ( id : asmmode_standard; @@ -1361,5 +1505,6 @@ const initialization RegisterAsmMode(asmmode_arm_att_info); + RegisterAsmMode(asmmode_arm_att_unified_info); RegisterAsmMode(asmmode_arm_standard_info); end. diff --git a/fpcsrc/compiler/arm/rarmcon.inc b/fpcsrc/compiler/arm/rarmcon.inc index 3d5cb5e7..5eccbc81 100644 --- a/fpcsrc/compiler/arm/rarmcon.inc +++ b/fpcsrc/compiler/arm/rarmcon.inc @@ -123,3 +123,10 @@ NR_BASEPRI = tregister($0500001F); NR_BASEPRI_MAX = tregister($05000020); NR_FAULTMASK = tregister($05000021); NR_CONTROL = tregister($05000022); +NR_FPSID = tregister($05000023); +NR_MVFR1 = tregister($05000024); +NR_MVFR0 = tregister($05000025); +NR_FPEXC = tregister($05000026); +NR_APSR_nzcvq = tregister($05000027); +NR_APSR_g = tregister($05000028); +NR_APSR_nzcvqg = tregister($05000029); diff --git a/fpcsrc/compiler/arm/rarmdwa.inc b/fpcsrc/compiler/arm/rarmdwa.inc index 624996d8..d2e3292c 100644 --- a/fpcsrc/compiler/arm/rarmdwa.inc +++ b/fpcsrc/compiler/arm/rarmdwa.inc @@ -122,4 +122,11 @@ 0, 0, 0, +0, +0, +0, +0, +0, +0, +0, 0 diff --git a/fpcsrc/compiler/arm/rarmnor.inc b/fpcsrc/compiler/arm/rarmnor.inc index 5b7bb114..c4e9a706 100644 --- a/fpcsrc/compiler/arm/rarmnor.inc +++ b/fpcsrc/compiler/arm/rarmnor.inc @@ -1,2 +1,2 @@ { don't edit, this file is generated from armreg.dat } -124 +131 diff --git a/fpcsrc/compiler/arm/rarmnum.inc b/fpcsrc/compiler/arm/rarmnum.inc index 73d011e1..16002ed6 100644 --- a/fpcsrc/compiler/arm/rarmnum.inc +++ b/fpcsrc/compiler/arm/rarmnum.inc @@ -122,4 +122,11 @@ tregister($0500001E), tregister($0500001F), tregister($05000020), tregister($05000021), -tregister($05000022) +tregister($05000022), +tregister($05000023), +tregister($05000024), +tregister($05000025), +tregister($05000026), +tregister($05000027), +tregister($05000028), +tregister($05000029) diff --git a/fpcsrc/compiler/arm/rarmrni.inc b/fpcsrc/compiler/arm/rarmrni.inc index be4c8f35..cd3dc04a 100644 --- a/fpcsrc/compiler/arm/rarmrni.inc +++ b/fpcsrc/compiler/arm/rarmrni.inc @@ -122,4 +122,11 @@ 120, 121, 122, -123 +123, +124, +125, +126, +127, +128, +129, +130 diff --git a/fpcsrc/compiler/arm/rarmsri.inc b/fpcsrc/compiler/arm/rarmsri.inc index 6eca1421..1f5dabb4 100644 --- a/fpcsrc/compiler/arm/rarmsri.inc +++ b/fpcsrc/compiler/arm/rarmsri.inc @@ -1,7 +1,10 @@ { don't edit, this file is generated from armreg.dat } 0, 110, +129, 92, +128, +130, 120, 121, 123, @@ -65,11 +68,15 @@ 23, 24, 122, +127, 90, +124, 114, 113, 111, 117, +126, +125, 109, 119, 118, @@ -104,7 +111,6 @@ 53, 28, 55, -71, 56, 58, 59, @@ -116,6 +122,7 @@ 68, 29, 70, +71, 31, 32, 34, diff --git a/fpcsrc/compiler/arm/rarmsta.inc b/fpcsrc/compiler/arm/rarmsta.inc index bce1177c..db130cb1 100644 --- a/fpcsrc/compiler/arm/rarmsta.inc +++ b/fpcsrc/compiler/arm/rarmsta.inc @@ -122,4 +122,11 @@ 0, 0, 0, +0, +0, +0, +0, +0, +0, +0, 0 diff --git a/fpcsrc/compiler/arm/rarmstd.inc b/fpcsrc/compiler/arm/rarmstd.inc index 4fed2df7..1f9c8211 100644 --- a/fpcsrc/compiler/arm/rarmstd.inc +++ b/fpcsrc/compiler/arm/rarmstd.inc @@ -70,7 +70,7 @@ 's29', 'd14', 's30', -'s21', +'s31', 'd15', 'd16', 'd17', @@ -122,4 +122,11 @@ 'basepri', 'basepri_max', 'faultmask', -'control' +'control', +'fpsid', +'mvfr1', +'mvfr0', +'fpexc', +'apsr_nzcvq', +'apsr_g', +'apsr_nzcvqg' diff --git a/fpcsrc/compiler/arm/rarmsup.inc b/fpcsrc/compiler/arm/rarmsup.inc index 285c1e09..7baa8ad7 100644 --- a/fpcsrc/compiler/arm/rarmsup.inc +++ b/fpcsrc/compiler/arm/rarmsup.inc @@ -123,3 +123,10 @@ RS_BASEPRI = $1F; RS_BASEPRI_MAX = $20; RS_FAULTMASK = $21; RS_CONTROL = $22; +RS_FPSID = $23; +RS_MVFR1 = $24; +RS_MVFR0 = $25; +RS_FPEXC = $26; +RS_APSR_nzcvq = $27; +RS_APSR_g = $28; +RS_APSR_nzcvqg = $29; diff --git a/fpcsrc/compiler/assemble.pas b/fpcsrc/compiler/assemble.pas index 16c6272e..feb007f3 100644 --- a/fpcsrc/compiler/assemble.pas +++ b/fpcsrc/compiler/assemble.pas @@ -83,6 +83,7 @@ interface lastsectype : TAsmSectionType; procedure WriteSourceLine(hp: tailineinfo); procedure WriteTempalloc(hp: tai_tempalloc); + Function DoPipe:boolean; public {# Returns the complete path and executable name of the assembler program. @@ -271,7 +272,7 @@ Implementation TExternalAssembler *****************************************************************************} - Function DoPipe:boolean; + Function TExternalAssembler.DoPipe:boolean; begin DoPipe:=(cs_asm_pipe in current_settings.globalswitches) and (([cs_asm_extern,cs_asm_leave,cs_link_on_target] * current_settings.globalswitches) = []) and @@ -1224,6 +1225,10 @@ Implementation asd_reference: { ignore for now, but should be added} ; +{$ifdef ARM} + asd_thumb_func: + ObjData.ThumbFunc:=true; +{$endif ARM} else internalerror(2010011101); end; @@ -1368,6 +1373,9 @@ Implementation asd_reference: { ignore for now, but should be added} ; + asd_thumb_func: + { ignore for now, but should be added} + ; else internalerror(2010011102); end; @@ -1391,6 +1399,7 @@ Implementation objsymend : TObjSymbol; zerobuf : array[0..63] of byte; relative_reloc: boolean; + tmp : word; begin fillchar(zerobuf,sizeof(zerobuf),0); fillchar(objsym,sizeof(objsym),0); @@ -1514,6 +1523,11 @@ Implementation aitconst_darwin_dwarf_delta32, aitconst_darwin_dwarf_delta64: ObjData.writebytes(Tai_const(hp).value,tai_const(hp).size); + aitconst_half16bit: + begin + tmp:=Tai_const(hp).value div 2; + ObjData.writebytes(tmp,2); + end else internalerror(200603254); end; diff --git a/fpcsrc/compiler/cgbase.pas b/fpcsrc/compiler/cgbase.pas index 678192e9..dff6e84e 100644 --- a/fpcsrc/compiler/cgbase.pas +++ b/fpcsrc/compiler/cgbase.pas @@ -101,6 +101,12 @@ interface ,addr_dgroup // the data segment group ,addr_seg // used for getting the segment of an object, e.g. 'mov ax, SEG symbol' {$ENDIF} + {$IFDEF AARCH64} + ,addr_page + ,addr_pageoffset + ,addr_gotpage + ,addr_gotpageoffset + {$ENDIF AARCH64} ); @@ -329,6 +335,13 @@ interface OS_M8,OS_M16,OS_M32,OS_M64,OS_M128,OS_M256,OS_M8,OS_M16,OS_M32, OS_M64,OS_M128,OS_M256); + tcgsize2signed : array[tcgsize] of tcgsize = (OS_NO, + OS_S8,OS_S16,OS_S32,OS_S64,OS_S128,OS_S8,OS_S16,OS_S32,OS_S64,OS_S128, + OS_F32,OS_F64,OS_F80,OS_C64,OS_F128, + OS_M8,OS_M16,OS_M32,OS_M64,OS_M128,OS_M256,OS_M8,OS_M16,OS_M32, + OS_M64,OS_M128,OS_M256); + + tcgloc2str : array[TCGLoc] of string[12] = ( 'LOC_INVALID', 'LOC_VOID', diff --git a/fpcsrc/compiler/cghlcpu.pas b/fpcsrc/compiler/cghlcpu.pas index 7568553f..c9620e46 100644 --- a/fpcsrc/compiler/cghlcpu.pas +++ b/fpcsrc/compiler/cghlcpu.pas @@ -65,14 +65,14 @@ uses procedure a_cmp_reg_reg_label(list: TAsmList; size: tcgsize; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override; procedure a_call_reg(list: TAsmList; reg: tregister); override; procedure a_call_name(list: TAsmList; const s: string; weak: boolean); override; - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tcgsize; src, dst: TRegister); override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); override; end; implementation { thlbasecgcpu } - procedure thlbasecgcpu.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tcgsize; src, dst: TRegister); + procedure thlbasecgcpu.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); begin internalerror(2012042801); end; diff --git a/fpcsrc/compiler/cgobj.pas b/fpcsrc/compiler/cgobj.pas index ccf26f2d..4245ff4a 100644 --- a/fpcsrc/compiler/cgobj.pas +++ b/fpcsrc/compiler/cgobj.pas @@ -247,7 +247,7 @@ unit cgobj; procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);virtual; abstract; { bit scan instructions } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tcgsize; src, dst: TRegister); virtual; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); virtual; { Multiplication with doubling result size. dstlo or dsthi may be NR_NO, in which case corresponding half of result is discarded. } @@ -865,7 +865,14 @@ implementation ref : treference; tmpreg : tregister; begin - cgpara.check_simple_location; + if assigned(cgpara.location^.next) then + begin + tg.gethltemp(list,cgpara.def,cgpara.def.size,tt_persistent,ref); + a_load_reg_ref(list,size,size,r,ref); + a_load_ref_cgpara(list,size,ref,cgpara); + tg.ungettemp(list,ref); + exit; + end; paramanager.alloccgpara(list,cgpara); if cgpara.location^.shiftval<0 then begin @@ -2525,7 +2532,7 @@ implementation end; - procedure tcg.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tcgsize; src, dst: TRegister); + procedure tcg.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tcgsize; src, dst: TRegister); begin internalerror(2014070601); end; diff --git a/fpcsrc/compiler/cgutils.pas b/fpcsrc/compiler/cgutils.pas index fb2fea8c..738026ff 100644 --- a/fpcsrc/compiler/cgutils.pas +++ b/fpcsrc/compiler/cgutils.pas @@ -63,6 +63,12 @@ unit cgutils; addressmode : taddressmode; shiftmode : tshiftmode; {$endif arm} +{$ifdef aarch64} + symboldata : tlinkedlistitem; + shiftimm : byte; + addressmode : taddressmode; + shiftmode : tshiftmode; +{$endif aarch64} {$ifdef avr} addressmode : taddressmode; {$endif avr} diff --git a/fpcsrc/compiler/fpcdefs.inc b/fpcsrc/compiler/fpcdefs.inc index cf24905b..83e7c7f5 100644 --- a/fpcsrc/compiler/fpcdefs.inc +++ b/fpcsrc/compiler/fpcdefs.inc @@ -242,6 +242,7 @@ {$define cpurox} {$define cputargethasfixedstack} {$define cpurefshaveindexreg} + {$define SUPPORT_GET_FRAME} {$endif aarch64} {$IFDEF MACOS} diff --git a/fpcsrc/compiler/hlcg2ll.pas b/fpcsrc/compiler/hlcg2ll.pas index 6d50fd9d..bae865c1 100644 --- a/fpcsrc/compiler/hlcg2ll.pas +++ b/fpcsrc/compiler/hlcg2ll.pas @@ -171,7 +171,7 @@ unit hlcg2ll; procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override; { bit scan instructions } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); override; { fpu move instructions } procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); override; @@ -586,9 +586,9 @@ implementation cg.a_loadaddr_ref_reg(list,ref,r); end; - procedure thlcg2ll.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); + procedure thlcg2ll.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); begin - cg.a_bit_scan_reg_reg(list,reverse,def_cgsize(size),src,dst); + cg.a_bit_scan_reg_reg(list,reverse,def_cgsize(srcsize),def_cgsize(dstsize),src,dst); end; procedure thlcg2ll.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); diff --git a/fpcsrc/compiler/hlcgobj.pas b/fpcsrc/compiler/hlcgobj.pas index 5a938882..1bc55d54 100644 --- a/fpcsrc/compiler/hlcgobj.pas +++ b/fpcsrc/compiler/hlcgobj.pas @@ -301,7 +301,7 @@ unit hlcgobj; public { bit scan instructions (still need transformation to thlcgobj) } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); virtual; abstract; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); virtual; abstract; { fpu move instructions } procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); virtual; abstract; @@ -536,9 +536,9 @@ unit hlcgobj; public procedure gen_load_para_value(list:TAsmList);virtual; - protected { helpers called by gen_load_para_value } procedure g_copyvalueparas(p:TObject;arg:pointer);virtual; + protected procedure gen_loadfpu_loc_cgpara(list: TAsmList; size: tdef; const l: tlocation;const cgpara: tcgpara;locintsize: longint);virtual; procedure init_paras(p:TObject;arg:pointer); protected @@ -4140,7 +4140,7 @@ implementation begin {$ifdef arm} if GenerateThumbCode or GenerateThumb2Code then - list.concat(tai_thumb_func.create); + list.concat(tai_directive.create(asd_thumb_func,'')); {$endif arm} { "double link" all procedure entry symbols via .reference } { directives on darwin, because otherwise the linker } @@ -4523,7 +4523,11 @@ implementation if (tparavarsym(p).varspez=vs_value) then begin include(current_procinfo.flags,pi_needs_implicit_finally); - location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).localloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint)); + location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).localloc,href, + is_open_array(tparavarsym(p).vardef) or + ((target_info.system in systems_caller_copy_addr_value_para) and + paramanager.push_addr_param(vs_value,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)), + sizeof(pint)); if is_open_array(tparavarsym(p).vardef) then begin if paramanager.push_high_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption) then @@ -4543,7 +4547,8 @@ implementation end; end; { open arrays can contain elements requiring init/final code, so the else has been removed here } - if (tparavarsym(p).varspez=vs_value) and + if not(target_info.system in systems_caller_copy_addr_value_para) and + (tparavarsym(p).varspez=vs_value) and (is_open_array(tparavarsym(p).vardef) or is_array_of_const(tparavarsym(p).vardef)) then begin @@ -4581,7 +4586,11 @@ implementation if not((tparavarsym(p).vardef.typ=variantdef) and paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then begin - location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint)); + location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href, + is_open_array(tparavarsym(p).vardef) or + ((target_info.system in systems_caller_copy_addr_value_para) and + paramanager.push_addr_param(vs_value,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)), + sizeof(pint)); if is_open_array(tparavarsym(p).vardef) then begin if paramanager.push_high_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption) then @@ -4682,8 +4691,11 @@ implementation begin list:=TAsmList(arg); if (tsym(p).typ=paravarsym) and - (tparavarsym(p).varspez=vs_value) and - (paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then + ((vo_has_local_copy in tparavarsym(p).varoptions) or + (not(target_info.system in systems_caller_copy_addr_value_para) and + (is_open_array(tparavarsym(p).vardef) or + is_array_of_const(tparavarsym(p).vardef)) and + (tparavarsym(p).varspez=vs_value))) then begin { we have no idea about the alignment at the caller side } location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,true,1); diff --git a/fpcsrc/compiler/i386/cpuelf.pas b/fpcsrc/compiler/i386/cpuelf.pas index fd171e3e..7c6c36b2 100644 --- a/fpcsrc/compiler/i386/cpuelf.pas +++ b/fpcsrc/compiler/i386/cpuelf.pas @@ -496,6 +496,7 @@ implementation encodereloc: @elf_i386_encodeReloc; loadreloc: @elf_i386_loadReloc; loadsection: nil; + encodeflags: nil; ); as_i386_elf32_info : tasminfo = diff --git a/fpcsrc/compiler/i8086/n8086mem.pas b/fpcsrc/compiler/i8086/n8086mem.pas index 7d12ef92..0dc521b8 100644 --- a/fpcsrc/compiler/i8086/n8086mem.pas +++ b/fpcsrc/compiler/i8086/n8086mem.pas @@ -27,6 +27,7 @@ interface uses globtype, + symtype, cgbase,cpuinfo,cpubase, node,nmem,ncgmem,nx86mem,ni86mem; @@ -45,7 +46,7 @@ interface ti8086vecnode = class(tcgvecnode) protected function first_arraydef: tnode;override; - procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);override; + procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override; end; implementation @@ -53,7 +54,7 @@ implementation uses systems,globals,constexp, cutils,verbose, - symbase,symconst,symdef,symtable,symtype,symsym,symx86,symcpu, + symbase,symconst,symdef,symtable,symsym,symx86,symcpu, parabase,paramgr, aasmtai,aasmdata, nld,ncon,nadd,ncal,ncnv, @@ -212,13 +213,13 @@ implementation end; - procedure ti8086vecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint); + procedure ti8086vecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); var saveseg: TRegister; begin saveseg:=location.reference.segment; location.reference.segment:=NR_NO; - inherited update_reference_reg_mul(maybe_const_reg,l); + inherited; location.reference.segment:=saveseg; end; diff --git a/fpcsrc/compiler/jvm/hlcgcpu.pas b/fpcsrc/compiler/jvm/hlcgcpu.pas index 909c1870..96b9d683 100644 --- a/fpcsrc/compiler/jvm/hlcgcpu.pas +++ b/fpcsrc/compiler/jvm/hlcgcpu.pas @@ -114,7 +114,7 @@ uses procedure gen_exit_code(list: TAsmList); override; { unimplemented/unnecessary routines } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); override; procedure a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle); override; procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle); override; procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle); override; @@ -1884,7 +1884,7 @@ implementation { nothing } end; - procedure thlcgjvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: tdef; src, dst: tregister); + procedure thlcgjvm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); begin internalerror(2012090201); end; diff --git a/fpcsrc/compiler/m68k/n68kmem.pas b/fpcsrc/compiler/m68k/n68kmem.pas index d6cb270f..6c72fab5 100644 --- a/fpcsrc/compiler/m68k/n68kmem.pas +++ b/fpcsrc/compiler/m68k/n68kmem.pas @@ -27,12 +27,13 @@ interface uses globtype, + symtype, cgbase,cpuinfo,cpubase, node,nmem,ncgmem; type t68kvecnode = class(tcgvecnode) - procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);override; + procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); override; //procedure pass_generate_code;override; end; @@ -59,7 +60,7 @@ implementation { the live range of the LOC_CREGISTER will most likely overlap the } { the live range of the target LOC_(C)REGISTER) } { The passed register may be a LOC_CREGISTER as well. } - procedure t68kvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint); + procedure t68kvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); var hreg: tregister; scaled: boolean; diff --git a/fpcsrc/compiler/mips/cpuelf.pas b/fpcsrc/compiler/mips/cpuelf.pas index 1c2de17e..9beff745 100644 --- a/fpcsrc/compiler/mips/cpuelf.pas +++ b/fpcsrc/compiler/mips/cpuelf.pas @@ -1026,6 +1026,7 @@ implementation encodereloc: @elf_mips_encodeReloc; loadreloc: @elf_mips_loadReloc; loadsection: @elf_mips_loadSection; + encodeflags: nil; ); initialization diff --git a/fpcsrc/compiler/msg/errore.msg b/fpcsrc/compiler/msg/errore.msg index 7770f7d3..badfd1ab 100644 --- a/fpcsrc/compiler/msg/errore.msg +++ b/fpcsrc/compiler/msg/errore.msg @@ -3443,6 +3443,7 @@ new features, etc.): # 4 = x86_64 # 6 = 680x0 targets # 8 = 8086 (16-bit) targets +# a = AArch64 # A = ARM # e = in extended debug mode only # F = help for the 'fpc' binary (independent of the target compiler) @@ -3713,6 +3714,7 @@ F*2P_Set target CPU (arm,avr,i386,jvm,m68k,mips,mipsel,powerpc,powerpc64,spar 3*2Twince_Windows CE 4*2Tdarwin_Darwin/Mac OS X 4*2Tfreebsd_FreeBSD +4*2Tiphonesim_ iPhoneSimulator 4*2Tlinux_Linux 4*2Tnetbsd_NetBSD 4*2Topenbsd_OpenBSD @@ -3723,6 +3725,7 @@ F*2P_Set target CPU (arm,avr,i386,jvm,m68k,mips,mipsel,powerpc,powerpc64,spar 6*2Tlinux_Linux 6*2Tpalmos_PalmOS 8*2Tmsdos_MS-DOS (and compatible) +a*2Tdarwin_Darwin/iOS A*2Tandroid_Android A*2Tdarwin_Darwin/iPhoneOS/iOS A*2Tembedded_Embedded @@ -3777,6 +3780,7 @@ A*2WA_Specify native type application (Windows) 3*2Wb_Create a bundle instead of a library (Darwin) P*2Wb_Create a bundle instead of a library (Darwin) p*2Wb_Create a bundle instead of a library (Darwin) +a*2Wb_Create a bundle instead of a library (Darwin) A*2Wb_Create a bundle instead of a library (Darwin) 4*2Wb_Create a bundle instead of a library (Darwin) 3*2WB_Create a relocatable image (Windows, Symbian) @@ -3794,6 +3798,7 @@ P*2WC_Specify console type application (Classic Mac OS) A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows) 3*2We_Use external resources (Darwin) 4*2We_Use external resources (Darwin) +a*2We_Use external resources (Darwin) A*2We_Use external resources (Darwin) P*2We_Use external resources (Darwin) p*2We_Use external resources (Darwin) @@ -3804,6 +3809,7 @@ A*2WG_Specify graphic type application (Windows) P*2WG_Specify graphic type application (Classic Mac OS) 3*2Wi_Use internal resources (Darwin) 4*2Wi_Use internal resources (Darwin) +a*2Wi_Use internal resources (Darwin) A*2Wi_Use internal resources (Darwin) P*2Wi_Use internal resources (Darwin) p*2Wi_Use internal resources (Darwin) @@ -3827,6 +3833,8 @@ A*2Wpxxxx_Specify the controller type; see fpc -i or fpc -iu for possible values m*2Wpxxxx_Specify the controller type; see fpc -i or fpc -iu for possible values V*2Wpxxxx_Specify the controller type; see fpc -i or fpc -iu for possible values 3*2WP_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim) +4*2WP_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim) +a*2WP_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin) A*2WP_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin) 3*2WR_Generate relocation code (Windows) 4*2WR_Generate relocation code (Windows) diff --git a/fpcsrc/compiler/msgidx.inc b/fpcsrc/compiler/msgidx.inc index f70f6daf..53f3862f 100644 --- a/fpcsrc/compiler/msgidx.inc +++ b/fpcsrc/compiler/msgidx.inc @@ -1001,7 +1001,7 @@ const option_info=11024; option_help_pages=11025; - MsgTxtSize = 74662; + MsgTxtSize = 74840; MsgIdxMax : array[1..20] of longint=( 26,99,339,123,96,57,126,27,202,64, diff --git a/fpcsrc/compiler/ncal.pas b/fpcsrc/compiler/ncal.pas index b4a7627e..7b701558 100644 --- a/fpcsrc/compiler/ncal.pas +++ b/fpcsrc/compiler/ncal.pas @@ -200,6 +200,10 @@ interface fparainit, fparacopyback: tnode; procedure handlemanagedbyrefpara(orgparadef: tdef);virtual;abstract; + { on some targets, value parameters that are passed by reference must + be copied to a temp location by the caller (and then a reference to + this temp location must be passed) } + procedure copy_value_by_ref_para; public callparaflags : tcallparaflags; parasym : tparavarsym; @@ -591,6 +595,208 @@ implementation TCALLPARANODE ****************************************************************************} + procedure tcallparanode.copy_value_by_ref_para; + var + initstat, + copybackstat, + finistat: tstatementnode; + finiblock: tblocknode; + paratemp: ttempcreatenode; + arraysize, + arraybegin: tnode; + lefttemp: ttempcreatenode; + vardatatype, + temparraydef: tdef; + begin + { this routine is for targets where by-reference value parameters need + to be copied by the caller. It's basically the node-level equivalent + of thlcgobj.g_copyvalueparas } + + { in case of an array constructor, we don't need a copy since the array + constructor itself is already constructed on the fly (and hence if + it's modified by the caller, that's no problem) } + if not is_array_constructor(left.resultdef) then + begin + fparainit:=internalstatements(initstat); + fparacopyback:=internalstatements(copybackstat); + finiblock:=internalstatements(finistat); + paratemp:=nil; + + { making a copy of an open array, an array of const or a dynamic + array requires dynamic memory allocation since we don't know the + size at compile time } + if is_open_array(left.resultdef) or + is_array_of_const(left.resultdef) or + (is_dynamic_array(left.resultdef) and + is_open_array(parasym.vardef)) then + begin + paratemp:=ctempcreatenode.create(voidpointertype,voidpointertype.size,tt_persistent,true); + if is_dynamic_array(left.resultdef) then + begin + { note that in insert_typeconv, this dynamic array was + already converted into an open array (-> dereferenced) + and then its resultdef was restored to the original + dynamic array one -> get the address before treating it + as a dynamic array here } + { first restore the actual resultdef of left } + temparraydef:=left.resultdef; + left.resultdef:=parasym.vardef; + { get its address } + lefttemp:=ctempcreatenode.create(voidpointertype,voidpointertype.size,tt_persistent,true); + addstatement(initstat,lefttemp); + addstatement(finistat,ctempdeletenode.create(lefttemp)); + addstatement(initstat, + cassignmentnode.create( + ctemprefnode.create(lefttemp), + caddrnode.create_internal(left) + ) + ); + { restore the resultdef } + left.resultdef:=temparraydef; + { now treat that address (correctly) as the original + dynamic array to get its start and length } + arraybegin:=cvecnode.create( + ctypeconvnode.create_explicit(ctemprefnode.create(lefttemp), + left.resultdef), + genintconstnode(0) + ); + arraysize:=caddnode.create(muln, + geninlinenode(in_length_x,false, + ctypeconvnode.create_explicit(ctemprefnode.create(lefttemp), + left.resultdef) + ), + genintconstnode(tarraydef(left.resultdef).elementdef.size) + ); + end + else + begin + { no problem here that left is used multiple times, as + sizeof() will simply evaluate to the high parameter } + arraybegin:=left.getcopy; + arraysize:=geninlinenode(in_sizeof_x,false,left); + end; + addstatement(initstat,paratemp); + { paratemp:=getmem(sizeof(para)) } + addstatement(initstat, + cassignmentnode.create( + ctemprefnode.create(paratemp), + ccallnode.createintern('fpc_getmem', + ccallparanode.create( + arraysize.getcopy,nil + ) + ) + ) + ); + { move(para,temp,sizeof(arr)) (no "left.getcopy" below because + we replace left afterwards) } + addstatement(initstat, + ccallnode.createintern('MOVE', + ccallparanode.create( + arraysize, + ccallparanode.create( + cderefnode.create(ctemprefnode.create(paratemp)), + ccallparanode.create( + arraybegin,nil + ) + ) + ) + ) + ); + { no reference count increases, that's still done on the callee + side because for compatibility with targets that perform this + copy on the callee side, that should only be done for non- + assember functions (and we can't know that 100% certain here, + e.g. in case of external declarations) (*) } + + { free the memory again after the call: freemem(paratemp) } + addstatement(finistat, + ccallnode.createintern('fpc_freemem', + ccallparanode.create( + ctemprefnode.create(paratemp),nil + ) + ) + ); + { replace the original parameter with a dereference of the + temp typecasted to the same type as the original parameter + (don't free left, it has been reused above) } + left:=ctypeconvnode.create_internal( + cderefnode.create(ctemprefnode.create(paratemp)), + left.resultdef); + end + else if is_shortstring(parasym.vardef) then + begin + { the shortstring parameter may have a different size than the + parameter type -> assign and truncate/extend } + paratemp:=ctempcreatenode.create(parasym.vardef,parasym.vardef.size,tt_persistent,false); + addstatement(initstat,paratemp); + { assign shortstring } + addstatement(initstat, + cassignmentnode.create( + ctemprefnode.create(paratemp),left + ) + ); + { replace parameter with temp (don't free left, it has been + reused above) } + left:=ctemprefnode.create(paratemp); + end + else if parasym.vardef.typ=variantdef then + begin + vardatatype:=search_system_type('TVARDATA').typedef; + paratemp:=ctempcreatenode.create(vardatatype,vardatatype.size,tt_persistent,false); + addstatement(initstat,paratemp); + addstatement(initstat, + ccallnode.createintern('fpc_variant_copy_overwrite', + ccallparanode.create( + ctypeconvnode.create_explicit(ctemprefnode.create(paratemp), + vardatatype + ), + ccallparanode.create(ctypeconvnode.create_explicit(left, + vardatatype), + nil + ) + ) + ) + ); + { replace parameter with temp (don't free left, it has been + reused above) } + left:=ctypeconvnode.create_explicit(ctemprefnode.create(paratemp),parasym.vardef); + end + else if is_managed_type(left.resultdef) then + begin + { don't increase/decrease the reference count here, will be done by + the callee (see (*) above) -> typecast to array of byte + for the assignment to the temp } + temparraydef:=getarraydef(u8inttype,left.resultdef.size); + paratemp:=ctempcreatenode.create(temparraydef,temparraydef.size,tt_persistent,false); + addstatement(initstat,paratemp); + addstatement(initstat, + cassignmentnode.create( + ctemprefnode.create(paratemp), + ctypeconvnode.create_internal(left,temparraydef) + ) + ); + left:=ctypeconvnode.create_explicit(ctemprefnode.create(paratemp),left.resultdef); + end + else + begin + paratemp:=ctempcreatenode.create(left.resultdef,left.resultdef.size,tt_persistent,false); + addstatement(initstat,paratemp); + addstatement(initstat, + cassignmentnode.create(ctemprefnode.create(paratemp),left) + ); + { replace parameter with temp (don't free left, it has been + reused above) } + left:=ctemprefnode.create(paratemp); + end; + addstatement(finistat,ctempdeletenode.create(paratemp)); + addstatement(copybackstat,finiblock); + firstpass(fparainit); + firstpass(left); + firstpass(fparacopyback); + end; + end; + + constructor tcallparanode.create(expr,next : tnode); begin @@ -720,6 +926,7 @@ implementation tcallparanode(right).firstcallparan; if not assigned(left.resultdef) then get_paratype; + if assigned(parasym) and (target_info.system in systems_managed_vm) and (parasym.varspez in [vs_var,vs_out,vs_constref]) and @@ -728,6 +935,27 @@ implementation (left.nodetype<>nothingn) then handlemanagedbyrefpara(left.resultdef); + { for targets that have to copy "value parameters by reference" on the + caller side + + aktcallnode may not be assigned in case firstcallparan is called for + fake parameters to inline nodes (in that case, we don't have a real + call and hence no "caller side" either) + } + if assigned(aktcallnode) and + (target_info.system in systems_caller_copy_addr_value_para) and + ((assigned(parasym) and + (parasym.varspez=vs_value)) or + (cpf_varargs_para in callparaflags)) and + (left.nodetype<>nothingn) and + not(vo_has_local_copy in parasym.varoptions) and + ((not is_open_array(parasym.vardef) and + not is_array_of_const(parasym.vardef)) or + not(aktcallnode.procdefinition.proccalloption in cdecl_pocalls)) and + paramanager.push_addr_param(vs_value,parasym.vardef, + aktcallnode.procdefinition.proccalloption) then + copy_value_by_ref_para; + { does it need to load RTTI? } if assigned(parasym) and (parasym.varspez=vs_out) and (cs_create_pic in current_settings.moduleswitches) and @@ -2090,6 +2318,8 @@ implementation { A) set the appropriate objc_msgSend* variant to call } + { The AArch64 abi does not require special handling for struct returns } +{$ifndef aarch64} { record returned via implicit pointer } if paramanager.ret_in_param(resultdef,procdefinition) then begin @@ -2108,11 +2338,13 @@ implementation else if (resultdef.typ=floatdef) and not(cnf_inherited in callnodeflags) then msgsendname:='OBJC_MSGSEND_FPRET' -{$endif} +{$endif i386} { default } - else if not(cnf_inherited in callnodeflags) then + else +{$endif aarch64} + if not(cnf_inherited in callnodeflags) then msgsendname:='OBJC_MSGSEND' -{$if defined(onlymacosx10_6) or defined(arm) } +{$if defined(onlymacosx10_6) or defined(arm) or defined(aarch64)} else if (target_info.system in systems_objc_nfabi) then msgsendname:='OBJC_MSGSENDSUPER2' {$endif onlymacosx10_6 or arm} @@ -2573,10 +2805,10 @@ implementation if not assigned(right) then begin if assigned(procdefinition.owner.defowner) then - para.left:=cloadparentfpnode.create(tprocdef(procdefinition.owner.defowner)) + para.left:=cloadparentfpnode.create(tprocdef(procdefinition.owner.defowner),lpf_forpara) { exceptfilters called from main level are not owned } else if procdefinition.proctypeoption=potype_exceptfilter then - para.left:=cloadparentfpnode.create(current_procinfo.procdef) + para.left:=cloadparentfpnode.create(current_procinfo.procdef,lpf_forpara) else internalerror(200309287); end @@ -2870,8 +3102,6 @@ implementation statements : tstatementnode; converted_result_data : ttempcreatenode; calltype: tdispcalltype; - label - errorexit; begin result:=nil; candidates:=nil; @@ -2879,460 +3109,462 @@ implementation oldcallnode:=aktcallnode; aktcallnode:=self; - { determine length of parameter list } - pt:=tcallparanode(left); - paralength:=0; - while assigned(pt) do - begin - inc(paralength); - pt:=tcallparanode(pt.right); - end; + try + { determine length of parameter list } + pt:=tcallparanode(left); + paralength:=0; + while assigned(pt) do + begin + inc(paralength); + pt:=tcallparanode(pt.right); + end; - { determine the type of the parameters } - if assigned(left) then - begin - tcallparanode(left).get_paratype; - if codegenerror then - goto errorexit; - end; + { determine the type of the parameters } + if assigned(left) then + begin + tcallparanode(left).get_paratype; + if codegenerror then + exit; + end; - if assigned(methodpointer) then - typecheckpass(methodpointer); + if assigned(methodpointer) then + typecheckpass(methodpointer); - { procedure variable ? } - if assigned(right) then - begin - set_varstate(right,vs_read,[vsf_must_be_valid]); - typecheckpass(right); - if codegenerror then - exit; + { procedure variable ? } + if assigned(right) then + begin + set_varstate(right,vs_read,[vsf_must_be_valid]); + typecheckpass(right); + if codegenerror then + exit; - procdefinition:=tabstractprocdef(right.resultdef); + procdefinition:=tabstractprocdef(right.resultdef); - { Compare parameters from right to left } - paraidx:=procdefinition.Paras.count-1; - { Skip default parameters } - if not(po_varargs in procdefinition.procoptions) then - begin - { ignore hidden parameters } - while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do - dec(paraidx); - for i:=1 to procdefinition.maxparacount-paralength do - begin - if paraidx<0 then - internalerror(200402265); - if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then - begin - CGMessage1(parser_e_wrong_parameter_size,''); - goto errorexit; - end; + { Compare parameters from right to left } + paraidx:=procdefinition.Paras.count-1; + { Skip default parameters } + if not(po_varargs in procdefinition.procoptions) then + begin + { ignore hidden parameters } + while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do dec(paraidx); - end; - end; - while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do - dec(paraidx); - pt:=tcallparanode(left); - lastpara:=paralength; - while (paraidx>=0) and assigned(pt) do - begin - { only goto next para if we're out of the varargs } - if not(po_varargs in procdefinition.procoptions) or - (lastpara<=procdefinition.maxparacount) then - begin - repeat - dec(paraidx); - until (paraidx<0) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions); - end; - pt:=tcallparanode(pt.right); - dec(lastpara); - end; - if assigned(pt) or - ((paraidx>=0) and - not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)) then - begin - if assigned(pt) then - current_filepos:=pt.fileinfo; - CGMessage1(parser_e_wrong_parameter_size,''); - goto errorexit; - end; - end - else - { not a procedure variable } - begin - { do we know the procedure to call ? } - if not(assigned(procdefinition)) then - begin - { ignore possible private for properties or in delphi mode for anon. inherited (FK) } - ignorevisibility:=(nf_isproperty in flags) or - ((m_delphi in current_settings.modeswitches) and (cnf_anon_inherited in callnodeflags)); - candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,ignorevisibility, - not(nf_isproperty in flags),cnf_objc_id_call in callnodeflags,cnf_unit_specified in callnodeflags, - callnodeflags*[cnf_anon_inherited,cnf_inherited]=[],cnf_anon_inherited in callnodeflags); - - { no procedures found? then there is something wrong - with the parameter size or the procedures are - not accessible } - if candidates.count=0 then - begin - { when it's an auto inherited call and there - is no procedure found, but the procedures - were defined with overload directive and at - least two procedures are defined then we ignore - this inherited by inserting a nothingn. Only - do this ugly hack in Delphi mode as it looks more - like a bug. It's also not documented } - if (m_delphi in current_settings.modeswitches) and - (cnf_anon_inherited in callnodeflags) and - (symtableprocentry.owner.symtabletype=ObjectSymtable) and - (po_overload in tprocdef(symtableprocentry.ProcdefList[0]).procoptions) and - (symtableprocentry.ProcdefList.Count>=2) then - result:=cnothingnode.create - else - begin - { in tp mode we can try to convert to procvar if - there are no parameters specified } - if not(assigned(left)) and - not(cnf_inherited in callnodeflags) and - ((m_tp_procvar in current_settings.modeswitches) or - (m_mac_procvar in current_settings.modeswitches)) and - (not assigned(methodpointer) or - (methodpointer.nodetype <> typen)) then - begin - hpt:=cloadnode.create(tprocsym(symtableprocentry),symtableproc); - if assigned(methodpointer) then - tloadnode(hpt).set_mp(methodpointer.getcopy); - typecheckpass(hpt); - result:=hpt; - end - else - begin - CGMessagePos1(fileinfo,parser_e_wrong_parameter_size,symtableprocentry.realname); - symtableprocentry.write_parameter_lists(nil); - end; - end; - candidates.free; - goto errorexit; - end; + for i:=1 to procdefinition.maxparacount-paralength do + begin + if paraidx<0 then + internalerror(200402265); + if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then + begin + CGMessage1(parser_e_wrong_parameter_size,''); + exit; + end; + dec(paraidx); + end; + end; + while (paraidx>=0) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do + dec(paraidx); + pt:=tcallparanode(left); + lastpara:=paralength; + while (paraidx>=0) and assigned(pt) do + begin + { only goto next para if we're out of the varargs } + if not(po_varargs in procdefinition.procoptions) or + (lastpara<=procdefinition.maxparacount) then + begin + repeat + dec(paraidx); + until (paraidx<0) or not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions); + end; + pt:=tcallparanode(pt.right); + dec(lastpara); + end; + if assigned(pt) or + ((paraidx>=0) and + not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)) then + begin + if assigned(pt) then + current_filepos:=pt.fileinfo; + CGMessage1(parser_e_wrong_parameter_size,''); + exit; + end; + end + else + { not a procedure variable } + begin + { do we know the procedure to call ? } + if not(assigned(procdefinition)) then + begin + { ignore possible private for properties or in delphi mode for anon. inherited (FK) } + ignorevisibility:=(nf_isproperty in flags) or + ((m_delphi in current_settings.modeswitches) and (cnf_anon_inherited in callnodeflags)); + candidates:=tcallcandidates.create(symtableprocentry,symtableproc,left,ignorevisibility, + not(nf_isproperty in flags),cnf_objc_id_call in callnodeflags,cnf_unit_specified in callnodeflags, + callnodeflags*[cnf_anon_inherited,cnf_inherited]=[],cnf_anon_inherited in callnodeflags); + + { no procedures found? then there is something wrong + with the parameter size or the procedures are + not accessible } + if candidates.count=0 then + begin + { when it's an auto inherited call and there + is no procedure found, but the procedures + were defined with overload directive and at + least two procedures are defined then we ignore + this inherited by inserting a nothingn. Only + do this ugly hack in Delphi mode as it looks more + like a bug. It's also not documented } + if (m_delphi in current_settings.modeswitches) and + (cnf_anon_inherited in callnodeflags) and + (symtableprocentry.owner.symtabletype=ObjectSymtable) and + (po_overload in tprocdef(symtableprocentry.ProcdefList[0]).procoptions) and + (symtableprocentry.ProcdefList.Count>=2) then + result:=cnothingnode.create + else + begin + { in tp mode we can try to convert to procvar if + there are no parameters specified } + if not(assigned(left)) and + not(cnf_inherited in callnodeflags) and + ((m_tp_procvar in current_settings.modeswitches) or + (m_mac_procvar in current_settings.modeswitches)) and + (not assigned(methodpointer) or + (methodpointer.nodetype <> typen)) then + begin + hpt:=cloadnode.create(tprocsym(symtableprocentry),symtableproc); + if assigned(methodpointer) then + tloadnode(hpt).set_mp(methodpointer.getcopy); + typecheckpass(hpt); + result:=hpt; + end + else + begin + CGMessagePos1(fileinfo,parser_e_wrong_parameter_size,symtableprocentry.realname); + symtableprocentry.write_parameter_lists(nil); + end; + end; + candidates.free; + exit; + end; - { Retrieve information about the candidates } - candidates.get_information; + { Retrieve information about the candidates } + candidates.get_information; {$ifdef EXTDEBUG} - { Display info when multiple candidates are found } - if candidates.count>1 then - candidates.dump_info(V_Debug); + { Display info when multiple candidates are found } + if candidates.count>1 then + candidates.dump_info(V_Debug); {$endif EXTDEBUG} - { Choose the best candidate and count the number of - candidates left } - cand_cnt:=candidates.choose_best(procdefinition, - assigned(left) and - not assigned(tcallparanode(left).right) and - (tcallparanode(left).left.resultdef.typ=variantdef)); + { Choose the best candidate and count the number of + candidates left } + cand_cnt:=candidates.choose_best(procdefinition, + assigned(left) and + not assigned(tcallparanode(left).right) and + (tcallparanode(left).left.resultdef.typ=variantdef)); - { All parameters are checked, check if there are any - procedures left } - if cand_cnt>0 then - begin - { Multiple candidates left? } - if cand_cnt>1 then - begin - CGMessage(type_e_cant_choose_overload_function); + { All parameters are checked, check if there are any + procedures left } + if cand_cnt>0 then + begin + { Multiple candidates left? } + if cand_cnt>1 then + begin + CGMessage(type_e_cant_choose_overload_function); {$ifdef EXTDEBUG} - candidates.dump_info(V_Hint); + candidates.dump_info(V_Hint); {$else EXTDEBUG} - candidates.list(false); + candidates.list(false); {$endif EXTDEBUG} - { we'll just use the first candidate to make the - call } - end; + { we'll just use the first candidate to make the + call } + end; - { assign procdefinition } - if symtableproc=nil then - symtableproc:=procdefinition.owner; - end - else - begin - { No candidates left, this must be a type error, - because wrong size is already checked. procdefinition - is filled with the first (random) definition that is - found. We use this definition to display a nice error - message that the wrong type is passed } - candidates.find_wrong_para; - candidates.list(true); + { assign procdefinition } + if symtableproc=nil then + symtableproc:=procdefinition.owner; + end + else + begin + { No candidates left, this must be a type error, + because wrong size is already checked. procdefinition + is filled with the first (random) definition that is + found. We use this definition to display a nice error + message that the wrong type is passed } + candidates.find_wrong_para; + candidates.list(true); {$ifdef EXTDEBUG} - candidates.dump_info(V_Hint); + candidates.dump_info(V_Hint); {$endif EXTDEBUG} - { We can not proceed, release all procs and exit } - candidates.free; - goto errorexit; - end; + { We can not proceed, release all procs and exit } + candidates.free; + exit; + end; - candidates.free; - end; { end of procedure to call determination } - end; + candidates.free; + end; { end of procedure to call determination } + end; - { check for hints (deprecated etc) } - if procdefinition.typ = procdef then - check_hints(tprocdef(procdefinition).procsym,tprocdef(procdefinition).symoptions,tprocdef(procdefinition).deprecatedmsg); + { check for hints (deprecated etc) } + if procdefinition.typ = procdef then + check_hints(tprocdef(procdefinition).procsym,tprocdef(procdefinition).symoptions,tprocdef(procdefinition).deprecatedmsg); - { add reference to corresponding procsym; may not be the one - originally found/passed to the constructor because of overloads } - if procdefinition.typ = procdef then - addsymref(tprocdef(procdefinition).procsym); + { add reference to corresponding procsym; may not be the one + originally found/passed to the constructor because of overloads } + if procdefinition.typ = procdef then + addsymref(tprocdef(procdefinition).procsym); - { add needed default parameters } - if (paralength=procdefinition.Paras.count then - internalerror(200306181); - if not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) then - inc(i); - inc(paraidx); - end; - while (paraidx=procdefinition.Paras.count then + internalerror(200306181); + if not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) then + inc(i); inc(paraidx); - until (paraidx>=procdefinition.paras.count) or - not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions); - end; - end; + end; + while (paraidx=procdefinition.paras.count) or + not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions); + end; + end; - { recursive call? } - if assigned(current_procinfo) and - (procdefinition=current_procinfo.procdef) then - include(current_procinfo.flags,pi_is_recursive); - - { handle predefined procedures } - is_const:=(po_internconst in procdefinition.procoptions) and - ((block_type in [bt_const,bt_type,bt_const_type,bt_var_type]) or - (assigned(left) and ((tcallparanode(left).left.nodetype in [realconstn,ordconstn]) - and (not assigned(tcallparanode(left).right) or (tcallparanode(left).right.nodetype in [realconstn,ordconstn]))))); - if (procdefinition.proccalloption=pocall_internproc) or is_const then - begin - if assigned(left) then - begin - { convert types to those of the prototype, this is required by functions like ror, rol, sar - some use however a dummy type (Typedfile) so this would break them } - if not(tprocdef(procdefinition).extnumber in [fpc_in_Reset_TypedFile,fpc_in_Rewrite_TypedFile]) then - begin - { bind parasyms to the callparanodes and insert hidden parameters } - bind_parasym; + { recursive call? } + if assigned(current_procinfo) and + (procdefinition=current_procinfo.procdef) then + include(current_procinfo.flags,pi_is_recursive); + + { handle predefined procedures } + is_const:=(po_internconst in procdefinition.procoptions) and + ((block_type in [bt_const,bt_type,bt_const_type,bt_var_type]) or + (assigned(left) and ((tcallparanode(left).left.nodetype in [realconstn,ordconstn]) + and (not assigned(tcallparanode(left).right) or (tcallparanode(left).right.nodetype in [realconstn,ordconstn]))))); + if (procdefinition.proccalloption=pocall_internproc) or is_const then + begin + if assigned(left) then + begin + { convert types to those of the prototype, this is required by functions like ror, rol, sar + some use however a dummy type (Typedfile) so this would break them } + if not(tprocdef(procdefinition).extnumber in [fpc_in_Reset_TypedFile,fpc_in_Rewrite_TypedFile]) then + begin + { bind parasyms to the callparanodes and insert hidden parameters } + bind_parasym; - { insert type conversions for parameters } - if assigned(left) then - tcallparanode(left).insert_typeconv; - end; + { insert type conversions for parameters } + if assigned(left) then + tcallparanode(left).insert_typeconv; + end; - { ptr and settextbuf need two args } - if assigned(tcallparanode(left).right) then - begin - hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,left); - left:=nil; - end - else - begin - hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,tcallparanode(left).left); - tcallparanode(left).left:=nil; - end; - end - else - hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,nil); - result:=hpt; - goto errorexit; - end; + { ptr and settextbuf need two args } + if assigned(tcallparanode(left).right) then + begin + hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,left); + left:=nil; + end + else + begin + hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,tcallparanode(left).left); + tcallparanode(left).left:=nil; + end; + end + else + hpt:=geninlinenode(tprocdef(procdefinition).extnumber,is_const,nil); + result:=hpt; + exit; + end; - { ensure that the result type is set } - if not(cnf_typedefset in callnodeflags) then - begin - { constructors return their current class type, not the type where the - constructor is declared, this can be different because of inheritance } - if (procdefinition.proctypeoption=potype_constructor) and - assigned(methodpointer) and - assigned(methodpointer.resultdef) and - (methodpointer.resultdef.typ=classrefdef) then - resultdef:=tclassrefdef(methodpointer.resultdef).pointeddef - else - { Member call to a (inherited) constructor from the class, the return - value is always self, so we change it to voidtype to generate an - error and to prevent users from generating non-working code - when they expect to clone the current instance, see bug 3662 (PFV) } + { ensure that the result type is set } + if not(cnf_typedefset in callnodeflags) then + begin + { constructors return their current class type, not the type where the + constructor is declared, this can be different because of inheritance } if (procdefinition.proctypeoption=potype_constructor) and - is_class(tprocdef(procdefinition).struct) and assigned(methodpointer) and - (methodpointer.nodetype=loadn) and - (loadnf_is_self in tloadnode(methodpointer).loadnodeflags) then - resultdef:=voidtype + assigned(methodpointer.resultdef) and + (methodpointer.resultdef.typ=classrefdef) then + resultdef:=tclassrefdef(methodpointer.resultdef).pointeddef else - resultdef:=procdefinition.returndef; - end - else - resultdef:=typedef; - - { Check object/class for methods } - if assigned(methodpointer) then - begin - { direct call to inherited abstract method, then we - can already give a error in the compiler instead - of a runtime error } - if (cnf_inherited in callnodeflags) and - (po_abstractmethod in procdefinition.procoptions) then - begin - if (m_delphi in current_settings.modeswitches) and - (cnf_anon_inherited in callnodeflags) then - begin - CGMessage(cg_h_inherited_ignored); - result:=cnothingnode.create; - exit; - end + { Member call to a (inherited) constructor from the class, the return + value is always self, so we change it to voidtype to generate an + error and to prevent users from generating non-working code + when they expect to clone the current instance, see bug 3662 (PFV) } + if (procdefinition.proctypeoption=potype_constructor) and + is_class(tprocdef(procdefinition).struct) and + assigned(methodpointer) and + (methodpointer.nodetype=loadn) and + (loadnf_is_self in tloadnode(methodpointer).loadnodeflags) then + resultdef:=voidtype else - CGMessage(cg_e_cant_call_abstract_method); - end; + resultdef:=procdefinition.returndef; + end + else + resultdef:=typedef; - { directly calling an interface/protocol/category/class helper - method via its type is not possible (always must be called via - the actual instance) } - if (methodpointer.nodetype=typen) and - (is_interface(methodpointer.resultdef) or - is_objc_protocol_or_category(methodpointer.resultdef)) then - CGMessage1(type_e_class_type_expected,methodpointer.resultdef.typename); - - { if an inherited con- or destructor should be } - { called in a con- or destructor then a warning } - { will be made } - { con- and destructors need a pointer to the vmt } - if (cnf_inherited in callnodeflags) and - (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) and - is_object(methodpointer.resultdef) and - not(current_procinfo.procdef.proctypeoption in [potype_constructor,potype_destructor]) then - CGMessage(cg_w_member_cd_call_from_method); - - if methodpointer.nodetype<>typen then - begin - { Remove all postfix operators } - hpt:=methodpointer; - while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do - hpt:=tunarynode(hpt).left; - - if ((hpt.nodetype=loadvmtaddrn) or - ((hpt.nodetype=loadn) and assigned(tloadnode(hpt).resultdef) and (tloadnode(hpt).resultdef.typ=classrefdef))) and - not (procdefinition.proctypeoption=potype_constructor) and - not (po_classmethod in procdefinition.procoptions) and - not (po_staticmethod in procdefinition.procoptions) then - { error: we are calling instance method from the class method/static method } - CGMessage(parser_e_only_class_members); - - if (procdefinition.proctypeoption=potype_constructor) and - assigned(symtableproc) and - (symtableproc.symtabletype=withsymtable) and - (tnode(twithsymtable(symtableproc).withrefnode).nodetype=temprefn) then - CGmessage(cg_e_cannot_call_cons_dest_inside_with); - - { skip (absolute and other simple) type conversions -- only now, - because the checks above have to take type conversions into - e.g. class reference types account } - hpt:=actualtargetnode(@hpt)^; - - { R.Init then R will be initialized by the constructor, - Also allow it for simple loads } - if (procdefinition.proctypeoption=potype_constructor) or - ((hpt.nodetype=loadn) and - (((methodpointer.resultdef.typ=objectdef) and - not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)) or - (methodpointer.resultdef.typ=recorddef) - ) - ) then - { a constructor will and a method may write something to } - { the fields } - set_varstate(methodpointer,vs_readwritten,[]) - else - set_varstate(methodpointer,vs_read,[vsf_must_be_valid]); - end; + { Check object/class for methods } + if assigned(methodpointer) then + begin + { direct call to inherited abstract method, then we + can already give a error in the compiler instead + of a runtime error } + if (cnf_inherited in callnodeflags) and + (po_abstractmethod in procdefinition.procoptions) then + begin + if (m_delphi in current_settings.modeswitches) and + (cnf_anon_inherited in callnodeflags) then + begin + CGMessage(cg_h_inherited_ignored); + result:=cnothingnode.create; + exit; + end + else + CGMessage(cg_e_cant_call_abstract_method); + end; - { if we are calling the constructor check for abstract - methods. Ignore inherited and member calls, because the - class is then already created } - if (procdefinition.proctypeoption=potype_constructor) and - not(cnf_inherited in callnodeflags) and - not(cnf_member_call in callnodeflags) then - verifyabstractcalls; - end - else - begin - { When this is method the methodpointer must be available } - if (right=nil) and - (procdefinition.owner.symtabletype in [ObjectSymtable,recordsymtable]) and - not procdefinition.no_self_node then - internalerror(200305061); - end; + { directly calling an interface/protocol/category/class helper + method via its type is not possible (always must be called via + the actual instance) } + if (methodpointer.nodetype=typen) and + (is_interface(methodpointer.resultdef) or + is_objc_protocol_or_category(methodpointer.resultdef)) then + CGMessage1(type_e_class_type_expected,methodpointer.resultdef.typename); + + { if an inherited con- or destructor should be } + { called in a con- or destructor then a warning } + { will be made } + { con- and destructors need a pointer to the vmt } + if (cnf_inherited in callnodeflags) and + (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) and + is_object(methodpointer.resultdef) and + not(current_procinfo.procdef.proctypeoption in [potype_constructor,potype_destructor]) then + CGMessage(cg_w_member_cd_call_from_method); + + if methodpointer.nodetype<>typen then + begin + { Remove all postfix operators } + hpt:=methodpointer; + while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do + hpt:=tunarynode(hpt).left; + + if ((hpt.nodetype=loadvmtaddrn) or + ((hpt.nodetype=loadn) and assigned(tloadnode(hpt).resultdef) and (tloadnode(hpt).resultdef.typ=classrefdef))) and + not (procdefinition.proctypeoption=potype_constructor) and + not (po_classmethod in procdefinition.procoptions) and + not (po_staticmethod in procdefinition.procoptions) then + { error: we are calling instance method from the class method/static method } + CGMessage(parser_e_only_class_members); + + if (procdefinition.proctypeoption=potype_constructor) and + assigned(symtableproc) and + (symtableproc.symtabletype=withsymtable) and + (tnode(twithsymtable(symtableproc).withrefnode).nodetype=temprefn) then + CGmessage(cg_e_cannot_call_cons_dest_inside_with); + + { skip (absolute and other simple) type conversions -- only now, + because the checks above have to take type conversions into + e.g. class reference types account } + hpt:=actualtargetnode(@hpt)^; + + { R.Init then R will be initialized by the constructor, + Also allow it for simple loads } + if (procdefinition.proctypeoption=potype_constructor) or + ((hpt.nodetype=loadn) and + (((methodpointer.resultdef.typ=objectdef) and + not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)) or + (methodpointer.resultdef.typ=recorddef) + ) + ) then + { a constructor will and a method may write something to } + { the fields } + set_varstate(methodpointer,vs_readwritten,[]) + else + set_varstate(methodpointer,vs_read,[vsf_must_be_valid]); + end; - { Set flag that the procedure uses varargs, also if they are not passed it is still - needed for x86_64 to pass the number of SSE registers used } - if po_varargs in procdefinition.procoptions then - include(callnodeflags,cnf_uses_varargs); + { if we are calling the constructor check for abstract + methods. Ignore inherited and member calls, because the + class is then already created } + if (procdefinition.proctypeoption=potype_constructor) and + not(cnf_inherited in callnodeflags) and + not(cnf_member_call in callnodeflags) then + verifyabstractcalls; + end + else + begin + { When this is method the methodpointer must be available } + if (right=nil) and + (procdefinition.owner.symtabletype in [ObjectSymtable,recordsymtable]) and + not procdefinition.no_self_node then + internalerror(200305061); + end; - { set the appropriate node flag if the call never returns } - if po_noreturn in procdefinition.procoptions then - include(callnodeflags,cnf_call_never_returns); + { Set flag that the procedure uses varargs, also if they are not passed it is still + needed for x86_64 to pass the number of SSE registers used } + if po_varargs in procdefinition.procoptions then + include(callnodeflags,cnf_uses_varargs); - { Change loading of array of const to varargs } - if assigned(left) and - is_array_of_const(tparavarsym(procdefinition.paras[procdefinition.paras.count-1]).vardef) and - (procdefinition.proccalloption in cdecl_pocalls) then - convert_carg_array_of_const; + { set the appropriate node flag if the call never returns } + if po_noreturn in procdefinition.procoptions then + include(callnodeflags,cnf_call_never_returns); - { bind parasyms to the callparanodes and insert hidden parameters } - bind_parasym; + { Change loading of array of const to varargs } + if assigned(left) and + is_array_of_const(tparavarsym(procdefinition.paras[procdefinition.paras.count-1]).vardef) and + (procdefinition.proccalloption in cdecl_pocalls) then + convert_carg_array_of_const; - { insert type conversions for parameters } - if assigned(left) then - tcallparanode(left).insert_typeconv; + { bind parasyms to the callparanodes and insert hidden parameters } + bind_parasym; - { dispinterface methode invoke? } - if assigned(methodpointer) and is_dispinterface(methodpointer.resultdef) then - begin - case procdefinition.proctypeoption of - potype_propgetter: calltype:=dct_propget; - potype_propsetter: calltype:=dct_propput; - else - calltype:=dct_method; - end; - { if the result is used, we've to insert a call to convert the type to be on the "safe side" } - if (cnf_return_value_used in callnodeflags) and not is_void(procdefinition.returndef) then - begin - result:=internalstatements(statements); - converted_result_data:=ctempcreatenode.create(procdefinition.returndef,sizeof(procdefinition.returndef), - tt_persistent,true); - addstatement(statements,converted_result_data); - addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data), - ctypeconvnode.create_internal( - translate_disp_call(methodpointer,parameters,calltype,'',tprocdef(procdefinition).dispid,procdefinition.returndef), - procdefinition.returndef))); - addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data)); - addstatement(statements,ctemprefnode.create(converted_result_data)); - end - else - result:=translate_disp_call(methodpointer,parameters,calltype,'',tprocdef(procdefinition).dispid,voidtype); + { insert type conversions for parameters } + if assigned(left) then + tcallparanode(left).insert_typeconv; - { don't free reused nodes } - methodpointer:=nil; - parameters:=nil; - end; + { dispinterface methode invoke? } + if assigned(methodpointer) and is_dispinterface(methodpointer.resultdef) then + begin + case procdefinition.proctypeoption of + potype_propgetter: calltype:=dct_propget; + potype_propsetter: calltype:=dct_propput; + else + calltype:=dct_method; + end; + { if the result is used, we've to insert a call to convert the type to be on the "safe side" } + if (cnf_return_value_used in callnodeflags) and not is_void(procdefinition.returndef) then + begin + result:=internalstatements(statements); + converted_result_data:=ctempcreatenode.create(procdefinition.returndef,sizeof(procdefinition.returndef), + tt_persistent,true); + addstatement(statements,converted_result_data); + addstatement(statements,cassignmentnode.create(ctemprefnode.create(converted_result_data), + ctypeconvnode.create_internal( + translate_disp_call(methodpointer,parameters,calltype,'',tprocdef(procdefinition).dispid,procdefinition.returndef), + procdefinition.returndef))); + addstatement(statements,ctempdeletenode.create_normal_temp(converted_result_data)); + addstatement(statements,ctemprefnode.create(converted_result_data)); + end + else + result:=translate_disp_call(methodpointer,parameters,calltype,'',tprocdef(procdefinition).dispid,voidtype); - errorexit: - aktcallnode:=oldcallnode; + { don't free reused nodes } + methodpointer:=nil; + parameters:=nil; + end; + + finally + aktcallnode:=oldcallnode; + end; end; @@ -3590,123 +3822,131 @@ implementation var para: tcallparanode; + oldcallnode: tcallnode; begin result:=nil; - { as pass_1 is never called on the methodpointer node, we must check - here that it's not a helper type } - if assigned(methodpointer) and - (methodpointer.nodetype=typen) and - is_objectpascal_helper(ttypenode(methodpointer).typedef) and - not ttypenode(methodpointer).helperallowed then - Message(parser_e_no_category_as_types); - - { can we get rid of the call? } - if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and - not(cnf_return_value_used in callnodeflags) and - (procdefinition.typ=procdef) and - tprocdef(procdefinition).isempty and - { allow only certain proc options } - ((tprocdef(procdefinition).procoptions-[po_none,po_classmethod,po_staticmethod, - po_interrupt,po_iocheck,po_assembler,po_msgstr,po_msgint,po_exports,po_external,po_overload, - po_nostackframe,po_has_mangledname,po_has_public_name,po_forward,po_global, - po_inline,po_compilerproc,po_has_importdll,po_has_importname,po_kylixlocal,po_dispid,po_delphi_nested_cc, - po_rtlproc,po_ignore_for_overload_resolution,po_auto_raised_visibility])=[]) then - begin - { check parameters for side effects } - para:=tcallparanode(left); - while assigned(para) do - begin - if (para.parasym.typ = paravarsym) and - ((para.parasym.refs>0) or - { array of consts are converted later on so we need to skip them here - else no error detection is done } - is_array_of_const(para.parasym.vardef) or - not(cs_opt_dead_values in current_settings.optimizerswitches) or - might_have_sideeffects(para.left)) then - break; - para:=tcallparanode(para.right); - end; - { finally, remove it if no parameter with side effect has been found } - if para=nil then - begin - result:=cnothingnode.create; - exit; - end; - end; - - { convert Objective-C calls into a message call } - if (procdefinition.typ=procdef) and - (po_objc in tprocdef(procdefinition).procoptions) then - begin - if not(cnf_objc_processed in callnodeflags) then - objc_convert_to_message_send; - end - else - begin - { The following don't apply to obj-c: obj-c methods can never be - inlined because they're always virtual and the destination can - change at run, and for the same reason we also can't perform - WPO on them (+ they have no constructors) } + oldcallnode:=aktcallnode; + aktcallnode:=self; - { Check if the call can be inlined, sets the cnf_do_inline flag } - check_inlining; + try + { as pass_1 is never called on the methodpointer node, we must check + here that it's not a helper type } + if assigned(methodpointer) and + (methodpointer.nodetype=typen) and + is_objectpascal_helper(ttypenode(methodpointer).typedef) and + not ttypenode(methodpointer).helperallowed then + Message(parser_e_no_category_as_types); + + { can we get rid of the call? } + if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and + not(cnf_return_value_used in callnodeflags) and + (procdefinition.typ=procdef) and + tprocdef(procdefinition).isempty and + { allow only certain proc options } + ((tprocdef(procdefinition).procoptions-[po_none,po_classmethod,po_staticmethod, + po_interrupt,po_iocheck,po_assembler,po_msgstr,po_msgint,po_exports,po_external,po_overload, + po_nostackframe,po_has_mangledname,po_has_public_name,po_forward,po_global, + po_inline,po_compilerproc,po_has_importdll,po_has_importname,po_kylixlocal,po_dispid,po_delphi_nested_cc, + po_rtlproc,po_ignore_for_overload_resolution,po_auto_raised_visibility])=[]) then + begin + { check parameters for side effects } + para:=tcallparanode(left); + while assigned(para) do + begin + if (para.parasym.typ = paravarsym) and + ((para.parasym.refs>0) or + { array of consts are converted later on so we need to skip them here + else no error detection is done } + is_array_of_const(para.parasym.vardef) or + not(cs_opt_dead_values in current_settings.optimizerswitches) or + might_have_sideeffects(para.left)) then + break; + para:=tcallparanode(para.right); + end; + { finally, remove it if no parameter with side effect has been found } + if para=nil then + begin + result:=cnothingnode.create; + exit; + end; + end; - { must be called before maybe_load_in_temp(methodpointer), because - it converts the methodpointer into a temp in case it's a call - (and we want to know the original call) - } - register_created_object_types; - end; + { convert Objective-C calls into a message call } + if (procdefinition.typ=procdef) and + (po_objc in tprocdef(procdefinition).procoptions) then + begin + if not(cnf_objc_processed in callnodeflags) then + objc_convert_to_message_send; + end + else + begin + { The following don't apply to obj-c: obj-c methods can never be + inlined because they're always virtual and the destination can + change at run, and for the same reason we also can't perform + WPO on them (+ they have no constructors) } + + { Check if the call can be inlined, sets the cnf_do_inline flag } + check_inlining; + + { must be called before maybe_load_in_temp(methodpointer), because + it converts the methodpointer into a temp in case it's a call + (and we want to know the original call) + } + register_created_object_types; + end; - { Maybe optimize the loading of the methodpointer using a temp. When the methodpointer - is a calln this is even required to not execute the calln twice. - This needs to be done after the resulttype pass, because in the resulttype we can still convert the - calln to a loadn (PFV) } - if assigned(methodpointer) then - maybe_load_in_temp(methodpointer); + { Maybe optimize the loading of the methodpointer using a temp. When the methodpointer + is a calln this is even required to not execute the calln twice. + This needs to be done after the resulttype pass, because in the resulttype we can still convert the + calln to a loadn (PFV) } + if assigned(methodpointer) then + maybe_load_in_temp(methodpointer); - { Create destination (temp or assignment-variable reuse) for function result if it not yet set } - maybe_create_funcret_node; + { Create destination (temp or assignment-variable reuse) for function result if it not yet set } + maybe_create_funcret_node; - { Insert the self,vmt,function result in the parameters } - gen_hidden_parameters; + { Insert the self,vmt,function result in the parameters } + gen_hidden_parameters; - { Remove useless nodes from init/final blocks } - { (simplify depends on typecheck info) } - if assigned(callinitblock) then - begin - typecheckpass(tnode(callinitblock)); - doinlinesimplify(tnode(callinitblock)); - end; - if assigned(callcleanupblock) then - begin - typecheckpass(tnode(callcleanupblock)); - doinlinesimplify(tnode(callcleanupblock)); - end; + { Remove useless nodes from init/final blocks } + { (simplify depends on typecheck info) } + if assigned(callinitblock) then + begin + typecheckpass(tnode(callinitblock)); + doinlinesimplify(tnode(callinitblock)); + end; + if assigned(callcleanupblock) then + begin + typecheckpass(tnode(callcleanupblock)); + doinlinesimplify(tnode(callcleanupblock)); + end; - { If a constructor calls another constructor of the same or of an - inherited class, some targets (jvm) have to generate different - entry code for the constructor. } - if (current_procinfo.procdef.proctypeoption=potype_constructor) and - (procdefinition.typ=procdef) and - (tprocdef(procdefinition).proctypeoption=potype_constructor) and - ([cnf_member_call,cnf_inherited] * callnodeflags <> []) then - current_procinfo.ConstructorCallingConstructor:=true; - - { object check helper will load VMT -> needs GOT } - if (cs_check_object in current_settings.localswitches) and - (cs_create_pic in current_settings.moduleswitches) then - include(current_procinfo.flags,pi_needs_got); - - { Continue with checking a normal call or generate the inlined code } - if cnf_do_inline in callnodeflags then - result:=pass1_inline - else - begin - mark_unregable_parameters; - result:=pass1_normal; - end; + { If a constructor calls another constructor of the same or of an + inherited class, some targets (jvm) have to generate different + entry code for the constructor. } + if (current_procinfo.procdef.proctypeoption=potype_constructor) and + (procdefinition.typ=procdef) and + (tprocdef(procdefinition).proctypeoption=potype_constructor) and + ([cnf_member_call,cnf_inherited] * callnodeflags <> []) then + current_procinfo.ConstructorCallingConstructor:=true; + + { object check helper will load VMT -> needs GOT } + if (cs_check_object in current_settings.localswitches) and + (cs_create_pic in current_settings.moduleswitches) then + include(current_procinfo.flags,pi_needs_got); + + { Continue with checking a normal call or generate the inlined code } + if cnf_do_inline in callnodeflags then + result:=pass1_inline + else + begin + mark_unregable_parameters; + result:=pass1_normal; + end; + finally + aktcallnode:=oldcallnode; + end; end; diff --git a/fpcsrc/compiler/ncgcnv.pas b/fpcsrc/compiler/ncgcnv.pas index da7dcc62..1a40eb57 100644 --- a/fpcsrc/compiler/ncgcnv.pas +++ b/fpcsrc/compiler/ncgcnv.pas @@ -176,6 +176,11 @@ interface if (nf_explicit in flags) and not(left.location.loc in [LOC_FLAGS,LOC_JUMP]) then begin + { overriding methods must be able to know in advance whether this + code path will be taken by checking expectloc, so they can call + the inherited method in that case } + if left.expectloc in [LOC_FLAGS,LOC_JUMP] then + internalerror(2014122901); 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 } diff --git a/fpcsrc/compiler/ncginl.pas b/fpcsrc/compiler/ncginl.pas index d6348d32..f1e5ef21 100644 --- a/fpcsrc/compiler/ncginl.pas +++ b/fpcsrc/compiler/ncginl.pas @@ -749,16 +749,12 @@ implementation secondpass(left); opsize:=tcgsize2unsigned[left.location.size]; - if opsize < OS_32 then - opsize:=OS_32; - - if (left.location.loc <> LOC_REGISTER) or - (left.location.size <> opsize) then + if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,cgsize_orddef(opsize),true); - location_reset(location,LOC_REGISTER,opsize); - location.register := cg.getintregister(current_asmdata.CurrAsmList,opsize); - cg.a_bit_scan_reg_reg(current_asmdata.CurrAsmList,reverse,opsize,left.location.register,location.register); + location_reset(location,LOC_REGISTER,def_cgsize(resultdef)); + location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size); + cg.a_bit_scan_reg_reg(current_asmdata.CurrAsmList,reverse,opsize,location.size,left.location.register,location.register); end; diff --git a/fpcsrc/compiler/ncgld.pas b/fpcsrc/compiler/ncgld.pas index 1473aafb..2fe9c184 100644 --- a/fpcsrc/compiler/ncgld.pas +++ b/fpcsrc/compiler/ncgld.pas @@ -768,9 +768,17 @@ implementation (right.resultdef.typ=floatdef) and (left.location.size<>right.location.size) then begin - hlcg.a_loadfpu_ref_ref(current_asmdata.CurrAsmList, - right.resultdef,left.resultdef, - right.location.reference,left.location.reference) + { assume that all float types can be handed by the + fpu if one can be handled by the fpu } + if not use_vectorfpu(left.resultdef) or + not use_vectorfpu(right.resultdef) then + hlcg.a_loadfpu_ref_ref(current_asmdata.CurrAsmList, + right.resultdef,left.resultdef, + right.location.reference,left.location.reference) + else + hlcg.a_loadmm_ref_ref(current_asmdata.CurrAsmList, + right.resultdef,left.resultdef, + right.location.reference,left.location.reference,mms_movescalar) end else begin diff --git a/fpcsrc/compiler/ncgmat.pas b/fpcsrc/compiler/ncgmat.pas index 82f75f4e..8a38b407 100644 --- a/fpcsrc/compiler/ncgmat.pas +++ b/fpcsrc/compiler/ncgmat.pas @@ -457,9 +457,9 @@ implementation procedure tcgshlshrnode.second_integer; var op : topcg; - opdef,right_opdef : tdef; + opdef: tdef; hcountreg : tregister; - opsize,right_opsize : tcgsize; + opsize : tcgsize; shiftval : longint; begin { determine operator } @@ -472,44 +472,51 @@ implementation {$ifdef cpunodefaultint} opsize:=left.location.size; opdef:=left.resultdef; - right_opsize:=opsize; - right_opdef:=opdef; {$else cpunodefaultint} - { load left operators in a register } - if is_signed(left.resultdef) then - begin - right_opsize:=OS_SINT; - right_opdef:=ossinttype; - {$ifdef cpu16bitalu} - if left.resultdef.size > 2 then - begin - opsize:=OS_S32; - opdef:=s32inttype; - end - else - {$endif cpu16bitalu} - begin - opsize:=OS_SINT; - opdef:=ossinttype - end; - end - else - begin - right_opsize:=OS_INT; - right_opdef:=osuinttype; - {$ifdef cpu16bitalu} - if left.resultdef.size > 2 then - begin - opsize:=OS_32; - opdef:=u32inttype; - end - else - {$endif cpu16bitalu} - begin - opsize:=OS_INT; - opdef:=osuinttype; - end; - end; + if left.resultdef.size<=4 then + begin + if is_signed(left.resultdef) then + begin + if (sizeof(aint)<4) and + (left.resultdef.size<=sizeof(aint)) then + begin + opsize:=OS_SINT; + opdef:=sinttype; + end + else + begin + opdef:=s32inttype; + opsize:=OS_S32 + end + end + else + begin + if (sizeof(aint)<4) and + (left.resultdef.size<=sizeof(aint)) then + begin + opsize:=OS_INT; + opdef:=uinttype; + end + else + begin + opdef:=u32inttype; + opsize:=OS_32; + end + end + end + else + begin + if is_signed(left.resultdef) then + begin + opdef:=s64inttype; + opsize:=OS_S64; + end + else + begin + opdef:=u64inttype; + opsize:=OS_64; + end; + end; {$endif cpunodefaultint} if not(left.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or @@ -538,14 +545,8 @@ implementation is done since most target cpu which will use this node do not support a shift count in a mem. location (cec) } - if not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) then - begin - hcountreg:=hlcg.getintregister(current_asmdata.CurrAsmList,right_opdef); - hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,right_opdef,right.location,hcountreg); - end - else - hcountreg:=right.location.register; - hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,hcountreg,left.location.register,location.register); + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,opdef,true); + hlcg.a_op_reg_reg_reg(current_asmdata.CurrAsmList,op,opdef,right.location.register,left.location.register,location.register); end; { shl/shr nodes return the same type as left, which can be different from opdef } diff --git a/fpcsrc/compiler/ncgmem.pas b/fpcsrc/compiler/ncgmem.pas index ad742fc3..1e8c24fd 100644 --- a/fpcsrc/compiler/ncgmem.pas +++ b/fpcsrc/compiler/ncgmem.pas @@ -27,7 +27,8 @@ unit ncgmem; interface uses - globtype,cgbase,cpuinfo,cpubase, + globtype,cgbase,cgutils,cpuinfo,cpubase, + symtype, node,nmem; type @@ -67,10 +68,12 @@ interface This routine should update location.reference correctly, so it points to the correct address. } - procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);virtual; - procedure update_reference_reg_packed(maybe_const_reg:tregister;l:aint);virtual; + procedure update_reference_reg_mul(maybe_const_reg: tregister;regsize: tdef; l: aint);virtual; + procedure update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l: aint);virtual; + procedure update_reference_offset(var ref: treference; index, mulsize: aint); virtual; procedure second_wideansistring;virtual; procedure second_dynamicarray;virtual; + function valid_index_size(size: tcgsize): boolean;virtual; public procedure pass_generate_code;override; end; @@ -81,11 +84,11 @@ implementation uses systems, cutils,cclasses,verbose,globals,constexp, - symconst,symbase,symtype,symdef,symsym,symcpu,symtable,defutil,paramgr, + symconst,symbase,symdef,symsym,symcpu,symtable,defutil,paramgr, aasmbase,aasmtai,aasmdata, procinfo,pass_2,parabase, pass_1,nld,ncon,nadd,ncnv,nutils, - cgutils,cgobj,hlcgobj, + cgobj,hlcgobj, tgobj,ncgutil,objcgutl, defcmp ; @@ -525,8 +528,8 @@ implementation } asmsym:=current_asmdata.RefAsmSymbol(vs.mangledname); reference_reset_symbol(tmpref,asmsym,0,sizeof(pint)); - location.reference.index:=cg.getaddressregister(current_asmdata.CurrAsmList); - cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,tmpref,location.reference.index); + location.reference.index:=hlcg.getintregister(current_asmdata.CurrAsmList,ptruinttype); + hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,ptruinttype,ptruinttype,tmpref,location.reference.index); { always packrecords C -> natural alignment } location.reference.alignment:=vs.vardef.alignment; end @@ -619,7 +622,7 @@ implementation { the live range of the LOC_CREGISTER will most likely overlap the } { the live range of the target LOC_(C)REGISTER) } { The passed register may be a LOC_CREGISTER as well. } - procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint); + procedure tcgvecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); var hreg: tregister; begin @@ -649,7 +652,7 @@ implementation { see remarks for tcgvecnode.update_reference_reg_mul above } - procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg:tregister;l:aint); + procedure tcgvecnode.update_reference_reg_packed(maybe_const_reg: tregister; regsize: tdef; l:aint); var sref: tsubsetreference; offsetreg, hreg: tregister; @@ -667,7 +670,7 @@ implementation {$endif not cpu64bitalu} ) then begin - update_reference_reg_mul(maybe_const_reg,l div 8); + update_reference_reg_mul(maybe_const_reg,regsize,l div 8); exit; end; if (l > 8*sizeof(aint)) then @@ -678,7 +681,7 @@ implementation cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_INT,l,hreg); { keep alignment for index } sref.ref.alignment := left.resultdef.alignment; - if not ispowerof2(sref.ref.alignment,temp) then + if not ispowerof2(packedbitsloadsize(l),temp) then internalerror(2006081201); alignpower:=temp; offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList); @@ -705,6 +708,12 @@ implementation end; + procedure tcgvecnode.update_reference_offset(var ref: treference; index, mulsize: aint); + begin + inc(ref.offset,index*mulsize); + end; + + procedure tcgvecnode.second_wideansistring; begin end; @@ -714,6 +723,13 @@ implementation end; + function tcgvecnode.valid_index_size(size: tcgsize): boolean; + begin + result:= + tcgsize2signed[size]=tcgsize2signed[OS_ADDR]; + end; + + procedure tcgvecnode.rangecheck_array; var hightree : tnode; @@ -859,6 +875,7 @@ implementation paraloc2 : tcgpara; subsetref : tsubsetreference; temp : longint; + indexdef : tdef; begin paraloc1.init; paraloc2.init; @@ -916,7 +933,7 @@ implementation { in ansistrings/widestrings S[1] is pchar(S)[0] } if not(cs_zerobasedstrings in current_settings.localswitches) then - dec(location.reference.offset,offsetdec); + update_reference_offset(location.reference,-1,offsetdec); end else if is_dynamic_array(left.resultdef) then begin @@ -971,7 +988,7 @@ implementation or is_64bitint(resultdef) {$endif not cpu64bitalu} ) then - dec(location.reference.offset,bytemulsize*tarraydef(left.resultdef).lowrange); + update_reference_offset(location.reference,-tarraydef(left.resultdef).lowrange,bytemulsize); if right.nodetype=ordconstn then begin @@ -992,10 +1009,10 @@ implementation { only orddefs are bitpacked } not is_ordinal(resultdef))) then begin - extraoffset:=bytemulsize*tordconstnode(right).value.svalue; - inc(location.reference.offset,extraoffset); - { adjust alignment after to this change } - location.reference.alignment:=newalignment(location.reference.alignment,extraoffset); + extraoffset:=tordconstnode(right).value.svalue; + update_reference_offset(location.reference,extraoffset,bytemulsize); + { adjust alignment after this change } + location.reference.alignment:=newalignment(location.reference.alignment,extraoffset*bytemulsize); { don't do this for floats etc.; needed to properly set the } { size for bitpacked arrays (e.g. a bitpacked array of } { enums who are size 2 but fit in one byte -> in the array } @@ -1008,10 +1025,10 @@ implementation begin subsetref.ref := location.reference; subsetref.ref.alignment := left.resultdef.alignment; - if not ispowerof2(subsetref.ref.alignment,temp) then + if not ispowerof2(packedbitsloadsize(resultdef.packedbitsize),temp) then internalerror(2006081212); alignpow:=temp; - inc(subsetref.ref.offset,((mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow)) shl alignpow); + update_reference_offset(subsetref.ref,(mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) shr (3+alignpow),1 shl alignpow); subsetref.bitindexreg := NR_NO; subsetref.startbit := (mulsize * (tordconstnode(right).value.svalue-tarraydef(left.resultdef).lowrange)) and ((1 shl (3+alignpow))-1); subsetref.bitlen := resultdef.packedbitsize; @@ -1056,8 +1073,7 @@ implementation replacenode(rightp^,taddnode(rightp^).left); end; end; - inc(location.reference.offset, - mulsize*extraoffset); + update_reference_offset(location.reference,extraoffset,mulsize); end; { calculate from left to right } if not(location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then @@ -1075,8 +1091,14 @@ implementation secondpass(right); { if mulsize = 1, we won't have to modify the index } - if not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or (right.location.size<>OS_ADDR) then - hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,ptruinttype,true); + if not(right.location.loc in [LOC_CREGISTER,LOC_REGISTER]) or + not valid_index_size(right.location.size) then + begin + hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,ptruinttype,true); + indexdef:=ptruinttype + end + else + indexdef:=right.resultdef; if isjump then begin @@ -1098,9 +1120,9 @@ implementation { insert the register and the multiplication factor in the reference } if not is_packed_array(left.resultdef) then - update_reference_reg_mul(right.location.register,mulsize) + update_reference_reg_mul(right.location.register,indexdef,mulsize) else - update_reference_reg_packed(right.location.register,mulsize); + update_reference_reg_packed(right.location.register,indexdef,mulsize); end; location.size:=newsize; diff --git a/fpcsrc/compiler/ncgutil.pas b/fpcsrc/compiler/ncgutil.pas index 2208ee1e..57c2ba55 100644 --- a/fpcsrc/compiler/ncgutil.pas +++ b/fpcsrc/compiler/ncgutil.pas @@ -598,82 +598,6 @@ implementation Init/Finalize Code ****************************************************************************} - procedure copyvalueparas(p:TObject;arg:pointer); - var - href : treference; - hreg : tregister; - list : TAsmList; - hsym : tparavarsym; - l : longint; - localcopyloc : tlocation; - sizedef : tdef; - begin - list:=TAsmList(arg); - if (tsym(p).typ=paravarsym) and - (tparavarsym(p).varspez=vs_value) and - (paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then - begin - { we have no idea about the alignment at the caller side } - hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,true,1); - if is_open_array(tparavarsym(p).vardef) or - is_array_of_const(tparavarsym(p).vardef) then - begin - { cdecl functions don't have a high pointer so it is not possible to generate - a local copy } - if not(current_procinfo.procdef.proccalloption in cdecl_pocalls) then - begin - hsym:=tparavarsym(get_high_value_sym(tparavarsym(p))); - if not assigned(hsym) then - internalerror(200306061); - sizedef:=getpointerdef(tparavarsym(p).vardef); - hreg:=hlcg.getaddressregister(list,sizedef); - if not is_packed_array(tparavarsym(p).vardef) then - hlcg.g_copyvaluepara_openarray(list,href,hsym.initialloc,tarraydef(tparavarsym(p).vardef),hreg) - else - internalerror(2006080401); -// cg.g_copyvaluepara_packedopenarray(list,href,hsym.intialloc,tarraydef(tparavarsym(p).vardef).elepackedbitsize,hreg); - hlcg.a_load_reg_loc(list,sizedef,sizedef,hreg,tparavarsym(p).initialloc); - end; - end - else - begin - { Allocate space for the local copy } - l:=tparavarsym(p).getsize; - localcopyloc.loc:=LOC_REFERENCE; - localcopyloc.size:=int_cgsize(l); - tg.GetLocal(list,l,tparavarsym(p).vardef,localcopyloc.reference); - { Copy data } - if is_shortstring(tparavarsym(p).vardef) then - begin - { this code is only executed before the code for the body and the entry/exit code is generated - so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore - } - include(current_procinfo.flags,pi_do_call); - hlcg.g_copyshortstring(list,href,localcopyloc.reference,tstringdef(tparavarsym(p).vardef)); - end - else if tparavarsym(p).vardef.typ = variantdef then - begin - { this code is only executed before the code for the body and the entry/exit code is generated - so we're allowed to include pi_do_call here; after pass1 is run, this isn't allowed anymore - } - include(current_procinfo.flags,pi_do_call); - hlcg.g_copyvariant(list,href,localcopyloc.reference,tvariantdef(tparavarsym(p).vardef)) - end - else - begin - { pass proper alignment info } - localcopyloc.reference.alignment:=tparavarsym(p).vardef.alignment; - cg.g_concatcopy(list,href,localcopyloc.reference,tparavarsym(p).vardef.size); - end; - { update localloc of varsym } - tg.Ungetlocal(list,tparavarsym(p).localloc.reference); - tparavarsym(p).localloc:=localcopyloc; - tparavarsym(p).initialloc:=localcopyloc; - end; - end; - end; - - { generates the code for incrementing the reference count of parameters and initialize out parameters } procedure init_paras(p:TObject;arg:pointer); @@ -698,7 +622,11 @@ implementation if not((tparavarsym(p).vardef.typ=variantdef) and paramanager.push_addr_param(tparavarsym(p).varspez,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)) then begin - hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href,is_open_array(tparavarsym(p).vardef),sizeof(pint)); + hlcg.location_get_data_ref(list,tparavarsym(p).vardef,tparavarsym(p).initialloc,href, + is_open_array(tparavarsym(p).vardef) or + ((target_info.system in systems_caller_copy_addr_value_para) and + paramanager.push_addr_param(vs_value,tparavarsym(p).vardef,current_procinfo.procdef.proccalloption)), + sizeof(pint)); if is_open_array(tparavarsym(p).vardef) then begin { open arrays do not contain correct element count in their rtti, @@ -864,12 +792,11 @@ implementation end; var - paraloc : pcgparalocation; - href : treference; - sizeleft : aint; -{$if defined(sparc) or defined(arm) or defined(mips)} - tempref : treference; -{$endif defined(sparc) or defined(arm) or defined(mips)} + paraloc : pcgparalocation; + href : treference; + sizeleft : aint; + alignment : longint; + tempref : treference; {$ifdef mips} tmpreg : tregister; {$endif mips} @@ -1085,7 +1012,38 @@ implementation end {$endif defined(cpu8bitalu)} else - internalerror(200410105); + begin + { this can happen if a parameter is spread over + multiple paralocs, e.g. if a record with two single + fields must be passed in two single precision + registers } + { does it fit in the register of destloc? } + sizeleft:=para.intsize; + if sizeleft<>vardef.size then + internalerror(2014122806); + if sizeleft<>tcgsize2size[destloc.size] then + internalerror(200410105); + { store everything first to memory, then load it in + destloc } + tg.gettemp(list,sizeleft,sizeleft,tt_persistent,tempref); + gen_alloc_regloc(list,destloc); + while sizeleft>0 do + begin + if not assigned(paraloc) then + internalerror(2014122807); + unget_para(paraloc^); + cg.a_load_cgparaloc_ref(list,paraloc^,tempref,sizeleft,newalignment(para.alignment,para.intsize-sizeleft)); + if (paraloc^.size=OS_NO) and + assigned(paraloc^.next) then + internalerror(2014122805); + inc(tempref.offset,tcgsize2size[paraloc^.size]); + dec(sizeleft,tcgsize2size[paraloc^.size]); + paraloc:=paraloc^.next; + end; + dec(tempref.offset,para.intsize); + cg.a_load_ref_reg(list,para.size,para.size,tempref,destloc.register); + tg.ungettemp(list,tempref); + end; end else begin @@ -1214,10 +1172,17 @@ implementation else {$endif not cpu64bitalu} begin - unget_para(paraloc^); - gen_alloc_regloc(list,destloc); - { from register to register -> alignment is irrelevant } - cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0); + if not assigned(paraloc^.next) then + begin + unget_para(paraloc^); + gen_alloc_regloc(list,destloc); + { from register to register -> alignment is irrelevant } + cg.a_load_cgparaloc_anyreg(list,destloc.size,paraloc^,destloc.register,0); + end + else + begin + internalerror(200410108); + end; { data could come in two memory locations, for now we simply ignore the sanity check (FK) if assigned(paraloc^.next) then @@ -1293,7 +1258,7 @@ implementation { generate copies of call by value parameters, must be done before the initialization and body is parsed because the refcounts are incremented using the local copies } - current_procinfo.procdef.parast.SymList.ForEachCall(@copyvalueparas,list); + current_procinfo.procdef.parast.SymList.ForEachCall(@hlcg.g_copyvalueparas,list); if not(po_assembler in current_procinfo.procdef.procoptions) then begin { initialize refcounted paras, and trash others. Needed here diff --git a/fpcsrc/compiler/ncnv.pas b/fpcsrc/compiler/ncnv.pas index 56bcdf41..7bdadfb9 100644 --- a/fpcsrc/compiler/ncnv.pas +++ b/fpcsrc/compiler/ncnv.pas @@ -2374,6 +2374,10 @@ implementation ((resultdef.typ=enumdef) and (left.resultdef.typ=objectdef))) or {$endif} + ( + is_void(left.resultdef) and + (left.nodetype=derefn) + ) or ( not(is_open_array(left.resultdef)) and not(is_array_constructor(left.resultdef)) and @@ -2388,10 +2392,6 @@ implementation { the softfloat code generates casts to record } (nf_internal in flags) )) - ) or - ( - is_void(left.resultdef) and - (left.nodetype=derefn) ) ) then CGMessage2(type_e_illegal_type_conversion,left.resultdef.typename,resultdef.typename) diff --git a/fpcsrc/compiler/ninl.pas b/fpcsrc/compiler/ninl.pas index a81bdfe4..7f8fed41 100644 --- a/fpcsrc/compiler/ninl.pas +++ b/fpcsrc/compiler/ninl.pas @@ -2631,6 +2631,10 @@ implementation if (left.resultdef.typ<>undefineddef) and paramanager.push_high_param(vs_value,left.resultdef,current_procinfo.procdef.proccalloption) then begin + { this should be an open array or array of const, both of + which can only be simple load nodes of parameters } + if left.nodetype<>loadn then + internalerror(2014120701); hightree:=load_high_value_node(tparavarsym(tloadnode(left).symtableentry)); if assigned(hightree) then begin diff --git a/fpcsrc/compiler/nld.pas b/fpcsrc/compiler/nld.pas index 2026b649..bec09106 100644 --- a/fpcsrc/compiler/nld.pas +++ b/fpcsrc/compiler/nld.pas @@ -326,7 +326,7 @@ implementation begin if assigned(left) then internalerror(200309289); - left:=cloadparentfpnode.create(tprocdef(symtable.defowner)); + left:=cloadparentfpnode.create(tprocdef(symtable.defowner),lpf_forload); { we can't inline the referenced parent procedure } exclude(tprocdef(symtable.defowner).procoptions,po_inline); { reference in nested procedures, variable needs to be in memory } @@ -484,7 +484,7 @@ implementation begin { parent frame pointer pointer as "self" } left.free; - left:=cloadparentfpnode.create(tprocdef(p.owner.defowner)); + left:=cloadparentfpnode.create(tprocdef(p.owner.defowner),lpf_forpara); end; end { we should never go from nested to non-nested } diff --git a/fpcsrc/compiler/nmem.pas b/fpcsrc/compiler/nmem.pas index 7953b086..f3135962 100644 --- a/fpcsrc/compiler/nmem.pas +++ b/fpcsrc/compiler/nmem.pas @@ -45,10 +45,18 @@ interface end; tloadvmtaddrnodeclass = class of tloadvmtaddrnode; + tloadparentfpkind = ( + { as parameter to a nested routine (current routine's frame) } + lpf_forpara, + { to load a local from a parent routine in the current nested routine + (some parent routine's frame) } + lpf_forload + ); tloadparentfpnode = class(tunarynode) parentpd : tprocdef; parentpdderef : tderef; - constructor create(pd:tprocdef);virtual; + kind: tloadparentfpkind; + constructor create(pd: tprocdef; fpkind: tloadparentfpkind);virtual; constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override; procedure ppuwrite(ppufile:tcompilerppufile);override; procedure buildderefimpl;override; @@ -240,7 +248,8 @@ implementation include(current_procinfo.flags,pi_needs_got); if left.nodetype<>typen then begin - if (is_objc_class_or_protocol(left.resultdef) or + if (target_info.system=system_aarch64_darwin) and + (is_objc_class_or_protocol(left.resultdef) or is_objcclassref(left.resultdef)) then begin { on non-fragile ABI platforms, the ISA pointer may be opaque @@ -294,7 +303,7 @@ implementation TLOADPARENTFPNODE *****************************************************************************} - constructor tloadparentfpnode.create(pd:tprocdef); + constructor tloadparentfpnode.create(pd: tprocdef; fpkind: tloadparentfpkind); begin inherited create(loadparentfpn,nil); if not assigned(pd) then @@ -302,6 +311,7 @@ implementation if (pd.parast.symtablelevel>current_procinfo.procdef.parast.symtablelevel) then internalerror(200309284); parentpd:=pd; + kind:=fpkind; end; @@ -309,6 +319,7 @@ implementation begin inherited ppuload(t,ppufile); ppufile.getderef(parentpdderef); + kind:=tloadparentfpkind(ppufile.getbyte); end; @@ -316,6 +327,7 @@ implementation begin inherited ppuwrite(ppufile); ppufile.putderef(parentpdderef); + ppufile.putbyte(byte(kind)); end; @@ -337,7 +349,8 @@ implementation begin result:= inherited docompare(p) and - (tloadparentfpnode(p).parentpd=parentpd); + (tloadparentfpnode(p).parentpd=parentpd) and + (tloadparentfpnode(p).kind=kind); end; @@ -347,6 +360,7 @@ implementation begin p:=tloadparentfpnode(inherited dogetcopy); p.parentpd:=parentpd; + p.kind:=kind; dogetcopy:=p; end; diff --git a/fpcsrc/compiler/objcgutl.pas b/fpcsrc/compiler/objcgutl.pas index 648378b3..cf113b07 100644 --- a/fpcsrc/compiler/objcgutl.pas +++ b/fpcsrc/compiler/objcgutl.pas @@ -91,7 +91,7 @@ implementation end; - { Used by PowerPC/64, ARM, and x86_64 } + { Used by PowerPC/64, ARM, x86_64 and AArch64 } tobjcrttiwriter_nonfragile = class(tobjcrttiwriter) protected ObjCEmptyCacheVar, diff --git a/fpcsrc/compiler/objcutil.pas b/fpcsrc/compiler/objcutil.pas index 00dfb27b..f26bceb9 100644 --- a/fpcsrc/compiler/objcutil.pas +++ b/fpcsrc/compiler/objcutil.pas @@ -153,13 +153,13 @@ end; { in case we are in a category method, we need the metaclass of the superclass class extended by this category (= metaclass of superclass of superclass) for the fragile abi, and the metaclass of the superclass for the non-fragile ABI } -{$if defined(onlymacosx10_6) or defined(arm) } +{$if defined(onlymacosx10_6) or defined(arm) or defined(aarch64)} { NOTE: those send2 methods are only available on Mac OS X 10.6 and later! (but also on all iPhone SDK revisions we support) } if (target_info.system in systems_objc_nfabi) then result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof)) else -{$endif onlymacosx10_6 or arm} +{$endif onlymacosx10_6 or arm aarch64} result:=cloadvmtaddrnode.create(ctypenode.create(tobjectdef(tclassrefdef(def).pointeddef).childof.childof)); tloadvmtaddrnode(result).forcall:=true; result:=cloadvmtaddrnode.create(result); @@ -183,14 +183,14 @@ end; tloadvmtaddrnode(result).forcall:=true; end; -{$if defined(onlymacosx10_6) or defined(arm) } +{$if defined(onlymacosx10_6) or defined(arm) or defined(aarch64)} { For the non-fragile ABI, the superclass send2 method itself loads the superclass. For the fragile ABI, we have to do this ourselves. NOTE: those send2 methods are only available on Mac OS X 10.6 and later! (but also on all iPhone SDK revisions we support) } if not(target_info.system in systems_objc_nfabi) then -{$endif onlymacosx10_6 or arm} +{$endif onlymacosx10_6 or arm or aarch64} result:=objcloadbasefield(result,'SUPERCLASS'); typecheckpass(result); end; diff --git a/fpcsrc/compiler/ogbase.pas b/fpcsrc/compiler/ogbase.pas index 4b1c54da..5489456f 100644 --- a/fpcsrc/compiler/ogbase.pas +++ b/fpcsrc/compiler/ogbase.pas @@ -68,6 +68,8 @@ interface {$endif i386} {$ifdef arm} RELOC_RELATIVE_24, + RELOC_RELATIVE_24_THUMB, + RELOC_RELATIVE_CALL_THUMB, {$endif arm} { Relative relocation } RELOC_RELATIVE, @@ -170,6 +172,10 @@ interface { Darwin asm is using indirect symbols resolving } indsymbol : TObjSymbol; +{$ifdef ARM} + ThumbFunc : boolean; +{$endif ARM} + constructor create(AList:TFPHashObjectList;const AName:string); function address:aword; procedure SetAddress(apass:byte;aobjsec:TObjSection;abind:TAsmsymbind;atyp:Tasmsymtype); @@ -287,6 +293,9 @@ interface public CurrPass : byte; ExecStack : boolean; +{$ifdef ARM} + ThumbFunc : boolean; +{$endif ARM} constructor create(const n:string);virtual; destructor destroy;override; { Sections } @@ -982,6 +991,9 @@ implementation FCachedAsmSymbolList:=TFPObjectList.Create(false); { section class type for creating of new sections } FCObjSection:=TObjSection; +{$ifdef ARM} + ThumbFunc:=false; +{$endif ARM} end; @@ -1166,6 +1178,11 @@ implementation result:=TObjSymbol(FObjSymbolList.Find(aname)); if not assigned(result) then result:=TObjSymbol.Create(FObjSymbolList,aname); + +{$ifdef ARM} + result.ThumbFunc:=ThumbFunc; + ThumbFunc:=false; +{$endif ARM} end; diff --git a/fpcsrc/compiler/ogcoff.pas b/fpcsrc/compiler/ogcoff.pas index e17d7763..3b58e828 100644 --- a/fpcsrc/compiler/ogcoff.pas +++ b/fpcsrc/compiler/ogcoff.pas @@ -261,9 +261,9 @@ interface TLSDIR_SIZE = $18; {$endif i386} {$ifdef arm} - COFF_MAGIC = $1c0; COFF_OPT_MAGIC = $10b; TLSDIR_SIZE = $18; + function COFF_MAGIC: word; {$endif arm} {$ifdef x86_64} COFF_MAGIC = $8664; @@ -422,6 +422,11 @@ implementation IMAGE_REL_ARM_BLX11 = $0009; IMAGE_REL_ARM_SECTION = $000E; { Section table index } IMAGE_REL_ARM_SECREL = $000F; { Offset within section } + IMAGE_REL_ARM_MOV32A = $0010; { 32-bit VA applied to MOVW+MOVT pair, added to existing imm (ARM) } + IMAGE_REL_ARM_MOV32T = $0011; { 32-bit VA applied to MOVW+MOVT pair, added to existing imm (THUMB) } + IMAGE_REL_ARM_BRANCH20T = $0012; { Thumb: 20 most significant bits of 32 bit B cond instruction } + IMAGE_REL_ARM_BRANCH24T = $0014; { Thumb: 24 most significant bits of 32 bit B uncond instruction } + IMAGE_REL_ARM_BLX23T = $0015; { 23 most significant bits of 32 bit BL/BLX instruction. Transformed to BLX if target is Thumb } {$endif arm} {$ifdef i386} @@ -913,6 +918,14 @@ const pemagic : array[0..3] of byte = ( if (relocval<>$3f) and (relocval<>0) then internalerror(200606085); { offset overflow } end; + RELOC_RELATIVE_24_THUMB: + begin + relocval:=longint(relocval - objsec.mempos - objreloc.dataoffset) shr 1 - 4; + address:=address or ((relocval shr 1) and $ffffff) or ((relocval and 1) shl 24); + relocval:=relocval shr 25; + if (relocval<>$3f) and (relocval<>0) then + internalerror(200606085); { offset overflow } + end; {$endif arm} {$ifdef x86_64} { 64 bit coff only } @@ -1009,10 +1022,9 @@ const pemagic : array[0..3] of byte = ( result:=aname else begin - { non-PECOFF targets lack rodata support. - TODO: WinCE likely supports it, but needs testing. } + { non-PECOFF targets lack rodata support } if (atype in [sec_rodata,sec_rodata_norel]) and - not (target_info.system in systems_windows) then + not (target_info.system in systems_all_windows) then atype:=sec_data; secname:=coffsecnames[atype]; if create_smartlink_sections and @@ -1038,8 +1050,7 @@ const pemagic : array[0..3] of byte = ( begin if (aType in [sec_rodata,sec_rodata_norel]) then begin - { TODO: WinCE needs testing } - if (target_info.system in systems_windows) then + if (target_info.system in systems_all_windows) then aType:=sec_rodata_norel else aType:=sec_data; @@ -1279,6 +1290,10 @@ const pemagic : array[0..3] of byte = ( rel.reloctype:=IMAGE_REL_ARM_ADDR32NB; RELOC_SECREL32 : rel.reloctype:=IMAGE_REL_ARM_SECREL; + RELOC_RELATIVE_24 : + rel.reloctype:=IMAGE_REL_ARM_BRANCH24; + RELOC_RELATIVE_24_THUMB: + rel.reloctype:=IMAGE_REL_ARM_BLX24; {$endif arm} {$ifdef i386} RELOC_RELATIVE : @@ -1597,6 +1612,8 @@ const pemagic : array[0..3] of byte = ( rel_type:=RELOC_RELATIVE_24; IMAGE_REL_ARM_SECREL: rel_type:=RELOC_SECREL32; + IMAGE_REL_ARM_BLX24: + rel_type:=RELOC_RELATIVE_24_THUMB; {$endif arm} {$ifdef i386} IMAGE_REL_I386_PCRLONG : @@ -2962,6 +2979,15 @@ const pemagic : array[0..3] of byte = ( DLLReader.Free; end; +{$ifdef arm} + function COFF_MAGIC: word; + begin + if GenerateThumb2Code and (current_settings.cputype>=cpu_armv7) then + COFF_MAGIC:=$1c4 // IMAGE_FILE_MACHINE_ARMNT + else + COFF_MAGIC:=$1c0; // IMAGE_FILE_MACHINE_ARM + end; +{$endif arm} {***************************************************************************** Initialize @@ -3045,7 +3071,7 @@ const pemagic : array[0..3] of byte = ( asmbin : ''; asmcmd : ''; supported_targets : [system_arm_wince]; - flags : [af_outputbinary]; + flags : [af_outputbinary,af_smartlink_sections]; labelprefix : '.L'; comment : ''; dollarsign: '$'; diff --git a/fpcsrc/compiler/ogelf.pas b/fpcsrc/compiler/ogelf.pas index 8a8ee338..938b7989 100644 --- a/fpcsrc/compiler/ogelf.pas +++ b/fpcsrc/compiler/ogelf.pas @@ -181,6 +181,7 @@ interface TEncodeRelocProc=function(objrel:TObjRelocation):byte; TLoadRelocProc=procedure(objrel:TObjRelocation); TLoadSectionProc=function(objinput:TElfObjInput;objdata:TObjData;const shdr:TElfsechdr;shindex:longint):boolean; + TEncodeFlagsProc=function:longword; TDynamicReloc=( dr_relative, dr_glob_dat, @@ -199,6 +200,7 @@ interface encodereloc: TEncodeRelocProc; loadreloc: TLoadRelocProc; loadsection: TLoadSectionProc; + encodeflags: TEncodeFlagsProc; end; @@ -966,6 +968,12 @@ implementation elfsym.st_name:=nameidx; elfsym.st_size:=objsym.size; elfsym.st_value:=objsym.address; + +{$ifdef ARM} + if objsym.ThumbFunc then + inc(elfsym.st_value); +{$endif ARM} + case objsym.bind of AB_LOCAL : begin @@ -1272,6 +1280,8 @@ implementation header.e_shnum:=nsections; header.e_ehsize:=sizeof(telfheader); header.e_shentsize:=sizeof(telfsechdr); + if assigned(ElfTarget.encodeflags) then + header.e_flags:=ElfTarget.encodeflags(); MaybeSwapHeader(header); writer.write(header,sizeof(header)); writer.writezeros($40-sizeof(header)); { align } @@ -2043,6 +2053,8 @@ implementation header.e_shnum:=ExeSectionList.Count+1; header.e_phnum:=segmentlist.count; header.e_ehsize:=sizeof(telfheader); + if assigned(ElfTarget.encodeflags) then + header.e_flags:=ElfTarget.encodeflags(); if assigned(EntrySym) then header.e_entry:=EntrySym.Address; header.e_shentsize:=sizeof(telfsechdr); diff --git a/fpcsrc/compiler/options.pas b/fpcsrc/compiler/options.pas index 86119ebc..c57425d5 100644 --- a/fpcsrc/compiler/options.pas +++ b/fpcsrc/compiler/options.pas @@ -646,6 +646,9 @@ begin {$ifdef i8086} '8', {$endif} +{$ifdef aarch64} + 'a', +{$endif} {$ifdef arm} 'A', {$endif} @@ -895,7 +898,7 @@ begin if MacVersionSet then exit; { check for deployment target set via environment variable } - if not(target_info.system in [system_i386_iphonesim,system_arm_darwin]) then + if not(target_info.system in [system_i386_iphonesim,system_arm_darwin,system_aarch64_darwin,system_x86_64_iphonesim]) then begin envstr:=GetEnvironmentVariable('MACOSX_DEPLOYMENT_TARGET'); if envstr<>'' then @@ -939,6 +942,12 @@ begin set_system_compvar('IPHONE_OS_VERSION_MIN_REQUIRED','30000'); iPhoneOSVersionMin:='3.0'; end; + system_aarch64_darwin, + system_x86_64_iphonesim: + begin + set_system_compvar('IPHONE_OS_VERSION_MIN_REQUIRED','70000'); + iPhoneOSVersionMin:='7.0'; + end else internalerror(2012031001); end; @@ -1487,10 +1496,16 @@ begin Message2(option_obsolete_switch_use_new,'-Fg','-Fl'); 'l' : begin - if ispara then - ParaLibraryPath.AddPath(sysrootpath,More,false) + if path_absolute(More) then + if ispara then + ParaLibraryPath.AddPath(sysrootpath,More,false) + else + LibrarySearchPath.AddPath(sysrootpath,More,true) else - LibrarySearchPath.AddPath(sysrootpath,More,true); + if ispara then + ParaLibraryPath.AddPath('',More,false) + else + LibrarySearchPath.AddPath('',More,true); end; 'L' : begin @@ -2210,7 +2225,7 @@ begin end; 'M': begin - if (target_info.system in (systems_darwin-[system_i386_iphonesim])) and + if (target_info.system in (systems_darwin-[system_i386_iphonesim,system_arm_darwin,system_aarch64_darwin,system_x86_64_iphonesim])) and ParseMacVersionMin(MacOSXVersionMin,iPhoneOSVersionMin,'MAC_OS_X_VERSION_MIN_REQUIRED',copy(More,2,255),false) then begin break; @@ -2243,7 +2258,7 @@ begin end; 'P': begin - if (target_info.system in [system_i386_iphonesim,system_arm_darwin]) and + if (target_info.system in [system_i386_iphonesim,system_arm_darwin,system_aarch64_darwin,system_x86_64_iphonesim]) and ParseMacVersionMin(iPhoneOSVersionMin,MacOSXVersionMin,'IPHONE_OS_VERSION_MIN_REQUIRED',copy(More,2,255),true) then begin break; @@ -3218,9 +3233,9 @@ begin { abs(long) is handled internally on all CPUs } def_system_macro('FPC_HAS_INTERNAL_ABS_LONG'); -{$if defined(x86_64) or defined(powerpc64)} +{$if defined(x86_64) or defined(powerpc64) or defined(cpuaarch64)} def_system_macro('FPC_HAS_INTERNAL_ABS_INT64'); -{$endif x86_64 or powerpc64} +{$endif x86_64 or powerpc64 or aarch64} def_system_macro('FPC_HAS_UNICODESTRING'); def_system_macro('FPC_RTTI_PACKSET1'); @@ -3403,6 +3418,12 @@ begin mm_huge: def_system_macro('FPC_MM_HUGE'); end; {$endif i8086} +{$ifdef aarch64} + def_system_macro('CPUAARCH64'); + def_system_macro('CPU64'); + def_system_macro('FPC_CURRENCY_IS_INT64'); + def_system_macro('FPC_COMP_IS_INT64'); +{$endif aarch64} if tf_cld in target_info.flags then if not UpdateTargetSwitchStr('CLD', init_settings.targetswitches, true) then @@ -3689,14 +3710,15 @@ begin case target_info.system of system_arm_darwin: begin - { set default cpu type to ARMv6 for Darwin unless specified otherwise, and fpu - to VFPv2 } + { set default cpu type to ARMv7 for Darwin unless specified otherwise, and fpu + to VFPv3 (that's what all 32 bit ARM iOS devices use nowadays) + } if not option.CPUSetExplicitly then - init_settings.cputype:=cpu_armv6; + init_settings.cputype:=cpu_armv7; if not option.OptCPUSetExplicitly then - init_settings.optimizecputype:=cpu_armv6; + init_settings.optimizecputype:=cpu_armv7; if not option.FPUSetExplicitly then - init_settings.fputype:=fpu_vfpv2; + init_settings.fputype:=fpu_vfpv3; end; system_arm_android: begin @@ -3796,7 +3818,7 @@ if (target_info.abi = abi_eabihf) then {$endif} def_system_macro('FPC_HAS_TYPE_SINGLE'); def_system_macro('FPC_HAS_TYPE_DOUBLE'); -{$if not defined(i386) and not defined(x86_64) and not defined(i8086)} +{$if not defined(i386) and not defined(x86_64) and not defined(i8086) and not defined(aarch64)} def_system_macro('FPC_INCLUDE_SOFTWARE_INT64_TO_DOUBLE'); {$endif} {$if defined(m68k)} @@ -3836,7 +3858,7 @@ if (target_info.abi = abi_eabihf) then {$endif ARM} { inline bsf/bsr implementation } -{$if defined(i386) or defined(x86_64)} +{$if defined(i386) or defined(x86_64) or defined(aarch64)} def_system_macro('FPC_HAS_INTERNAL_BSF'); def_system_macro('FPC_HAS_INTERNAL_BSR'); {$endif} diff --git a/fpcsrc/compiler/pparautl.pas b/fpcsrc/compiler/pparautl.pas index 9e066137..df9daa3f 100644 --- a/fpcsrc/compiler/pparautl.pas +++ b/fpcsrc/compiler/pparautl.pas @@ -308,11 +308,21 @@ implementation { We need a local copy for a value parameter when only the address is pushed. Open arrays and Array of Const are an exception because they are allocated at runtime and the - address that is pushed is patched } + address that is pushed is patched. + + Arrays passed to cdecl routines are special: they are pointers in + C and hence must be passed as such. Due to historical reasons, if + a cdecl routine is implemented in Pascal, we still make a copy on + the callee side. Do this the same on platforms that normally must + make a copy on the caller side, as otherwise the behaviour will + be different (and less perfomant) for routines implemented in C } if (varspez=vs_value) and paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and not(is_open_array(vardef) or - is_array_of_const(vardef)) then + is_array_of_const(vardef)) and + (not(target_info.system in systems_caller_copy_addr_value_para) or + ((pd.proccalloption in cdecl_pocalls) and + (vardef.typ=arraydef))) then include(varoptions,vo_has_local_copy); { needs high parameter ? } diff --git a/fpcsrc/compiler/ppu.pas b/fpcsrc/compiler/ppu.pas index d1c74f7a..a92fc106 100644 --- a/fpcsrc/compiler/ppu.pas +++ b/fpcsrc/compiler/ppu.pas @@ -188,7 +188,8 @@ const { 12 } 16 {'avr'}, { 13 } 32 {'mipsel'}, { 14 } 32 {'jvm'}, - { 15 } 16 {'i8086'} + { 15 } 16 {'i8086'}, + { 16 } 64 {'aarch64'} ); CpuAluBitSize : array[tsystemcpu] of longint = ( @@ -207,7 +208,8 @@ const { 12 } 8 {'avr'}, { 13 } 32 {'mipsel'}, { 14 } 64 {'jvm'}, - { 15 } 16 {'i8086'} + { 15 } 16 {'i8086'}, + { 16 } 64 {'aarch64'} ); {$endif generic_cpu} diff --git a/fpcsrc/compiler/psub.pas b/fpcsrc/compiler/psub.pas index def1535b..01944ae9 100644 --- a/fpcsrc/compiler/psub.pas +++ b/fpcsrc/compiler/psub.pas @@ -161,6 +161,12 @@ implementation Message(parser_h_inlining_disabled); exit; end; + if pi_calls_c_varargs in current_procinfo.flags then + begin + Message1(parser_h_not_supported_for_inline,'called C-style varargs functions'); + Message(parser_h_inlining_disabled); + exit; + end; { the compiler cannot handle inherited in inlined subroutines because it tries to search for self in the symtable, however, the symtable is not available } diff --git a/fpcsrc/compiler/psystem.pas b/fpcsrc/compiler/psystem.pas index 9e6a243d..6483272f 100644 --- a/fpcsrc/compiler/psystem.pas +++ b/fpcsrc/compiler/psystem.pas @@ -268,6 +268,10 @@ implementation create_fpu_types; s64currencytype:=corddef.create(scurrency,low(int64),high(int64)); {$endif arm} +{$ifdef aarch64} + create_fpu_types; + s64currencytype:=corddef.create(scurrency,low(int64),high(int64)); +{$endif aarch64} {$ifdef avr} s32floattype:=cfloatdef.create(s32real); s64floattype:=cfloatdef.create(s64real); @@ -734,7 +738,6 @@ implementation // aiclass[ait_labeled_instruction]:=tai_labeled_instruction; {$endif SPARC} {$ifdef arm} - aiclass[ait_thumb_func]:=tai_thumb_func; aiclass[ait_thumb_set]:=tai_thumb_set; {$endif arm} aiclass[ait_set]:=tai_set; diff --git a/fpcsrc/compiler/raatt.pas b/fpcsrc/compiler/raatt.pas index 734c7fe8..b07d8db4 100644 --- a/fpcsrc/compiler/raatt.pas +++ b/fpcsrc/compiler/raatt.pas @@ -287,12 +287,24 @@ unit raatt; end; {$endif POWERPC} {$if defined(ARM)} - { Thumb-2 instructions can have a .W postfix to indicate 32bit instructions + { + Thumb-2 instructions can have a .W postfix to indicate 32bit instructions, + Also in unified syntax sizes and types are indicated with something like a .
prefix for example } case c of '.': begin - actasmpattern:=actasmpattern+c; + if len>1 then + begin + while c in ['A'..'Z','a'..'z','0'..'9','_','.'] do + begin + inc(len); + actasmpattern[len]:=c; + c:=current_scanner.asmgetchar; + end; + actasmpattern[0]:=chr(len); + end; + {actasmpattern:=actasmpattern+c; c:=current_scanner.asmgetchar; if upcase(c) = 'W' then @@ -301,10 +313,22 @@ unit raatt; c:=current_scanner.asmgetchar; end else - internalerror(2010122301); + internalerror(2010122301);} end end; {$endif ARM} +{$ifdef aarch64} + { b.cond } + case c of + '.': + begin + repeat + actasmpattern:=actasmpattern+c; + c:=current_scanner.asmgetchar; + until not(c in ['a'..'z','A'..'Z']); + end; + end; +{$endif aarch64} { Opcode ? } If is_asmopcode(upper(actasmpattern)) then Begin @@ -1282,10 +1306,16 @@ unit raatt; while (actasmtoken=AS_DOT) do begin Consume(AS_DOT); - if actasmtoken=AS_ID then - s:=s+'.'+actasmpattern; - if not Consume(AS_ID) then + + { a record field could have the same name as a register } + if actasmtoken in [AS_ID,AS_REGISTER] then + begin + s:=s+'.'+actasmpattern; + consume(actasmtoken) + end + else begin + Consume(AS_ID); RecoverConsume(true); break; end; diff --git a/fpcsrc/compiler/rautils.pas b/fpcsrc/compiler/rautils.pas index d767d042..d8298821 100644 --- a/fpcsrc/compiler/rautils.pas +++ b/fpcsrc/compiler/rautils.pas @@ -69,6 +69,10 @@ type OPR_MODEFLAGS : (flags : tcpumodeflags); OPR_SPECIALREG: (specialreg : tregister; specialregflags : tspecialregflags); {$endif arm} +{$ifdef aarch64} + OPR_SHIFTEROP : (shifterop : tshifterop); + OPR_COND : (cc : tasmcond); +{$endif aarch64} end; TOperand = class @@ -1062,15 +1066,17 @@ end; {$ifdef ARM} OPR_REGSET: ai.loadregset(i-1,regtype,subreg,regset,usermode); - OPR_SHIFTEROP: - ai.loadshifterop(i-1,shifterop); - OPR_COND: - ai.loadconditioncode(i-1,cc); OPR_MODEFLAGS: ai.loadmodeflags(i-1,flags); OPR_SPECIALREG: ai.loadspecialreg(i-1,specialreg,specialregflags); {$endif ARM} +{$if defined(arm) or defined(aarch64)} + OPR_SHIFTEROP: + ai.loadshifterop(i-1,shifterop); + OPR_COND: + ai.loadconditioncode(i-1,cc); +{$endif arm or aarch64} { ignore wrong operand } OPR_NONE: ; diff --git a/fpcsrc/compiler/sparc/cpuelf.pas b/fpcsrc/compiler/sparc/cpuelf.pas index 027e7dce..1123ffb2 100644 --- a/fpcsrc/compiler/sparc/cpuelf.pas +++ b/fpcsrc/compiler/sparc/cpuelf.pas @@ -114,6 +114,7 @@ implementation encodereloc: @elf_sparc_encodeReloc; loadreloc: @elf_sparc_loadReloc; loadsection: nil; + encodeflags: nil; ); as_sparc_elf32_info : tasminfo = diff --git a/fpcsrc/compiler/symdef.pas b/fpcsrc/compiler/symdef.pas index bc9fc8b6..663a5956 100644 --- a/fpcsrc/compiler/symdef.pas +++ b/fpcsrc/compiler/symdef.pas @@ -2830,6 +2830,7 @@ implementation sc80real: if target_info.system in [system_i386_darwin, system_i386_iphonesim,system_x86_64_darwin, + system_x86_64_iphonesim, system_x86_64_linux,system_x86_64_freebsd, system_x86_64_openbsd,system_x86_64_netbsd, system_x86_64_solaris,system_x86_64_embedded, @@ -7504,7 +7505,7 @@ implementation begin if assigned(objc_fastenumeration) then exit; - if not(target_info.system in [system_arm_darwin,system_i386_iphonesim]) then + if not(target_info.system in [system_arm_darwin,system_i386_iphonesim,system_aarch64_darwin,system_x86_64_iphonesim]) then cocoaunit:='COCOAALL' else cocoaunit:='IPHONEALL'; @@ -7532,6 +7533,11 @@ implementation {$define use_vectorfpuimplemented} use_vectorfpu:=(current_settings.fputype in vfp_scalar); {$endif arm} +{$ifdef aarch64} +{$define use_vectorfpuimplemented} + use_vectorfpu:=true; +{$endif aarch64} + {$ifndef use_vectorfpuimplemented} use_vectorfpu:=false; {$endif} diff --git a/fpcsrc/compiler/systems.inc b/fpcsrc/compiler/systems.inc index bd9fff3f..c3ab6a12 100644 --- a/fpcsrc/compiler/systems.inc +++ b/fpcsrc/compiler/systems.inc @@ -49,7 +49,8 @@ cpu_avr, { 12 } cpu_mipsel, { 13 } cpu_jvm, { 14 } - cpu_i8086 { 15 } + cpu_i8086, { 15 } + cpu_aarch64 { 16 } ); tasmmode= (asmmode_none @@ -68,6 +69,7 @@ ,asmmode_avr_gas ,asmmode_i8086_intel ,asmmode_i8086_att + ,asmmode_arm_gas_unified ); (* IMPORTANT NOTE: @@ -165,7 +167,10 @@ system_mipsel_embedded, { 82 } system_i386_aros, { 83 } system_x86_64_aros, { 84 } - system_x86_64_dragonfly { 85 } + system_x86_64_dragonfly, { 85 } + system_aarch64_darwin, { 86 } + system_x86_64_iphonesim, { 87 } + system_aarch64_linux { 88 } ); type @@ -211,6 +216,7 @@ ,as_i8086_nasm ,as_i8086_nasmobj ,as_gas_powerpc_xcoff + ,as_arm_elf32 ,as_clang ); @@ -283,6 +289,7 @@ ,abi_powerpc_sysv,abi_powerpc_aix ,abi_eabi,abi_armeb,abi_eabihf ,abi_old_win32_gnu + ,abi_aarch64_darwin ); diff --git a/fpcsrc/compiler/systems.pas b/fpcsrc/compiler/systems.pas index 79339cc7..f7efda85 100644 --- a/fpcsrc/compiler/systems.pas +++ b/fpcsrc/compiler/systems.pas @@ -216,7 +216,7 @@ 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_alpha_linux,system_m68k_linux, - system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux]; + system_x86_6432_linux,system_mipseb_linux,system_mipsel_linux,system_aarch64_linux]; systems_dragonfly = [system_x86_64_dragonfly]; systems_freebsd = [system_i386_freebsd, system_x86_64_freebsd]; @@ -242,7 +242,8 @@ interface { all darwin systems } systems_darwin = [system_powerpc_darwin,system_i386_darwin, system_powerpc64_darwin,system_x86_64_darwin, - system_arm_darwin,system_i386_iphonesim]; + system_arm_darwin,system_i386_iphonesim, + system_aarch64_darwin,system_x86_64_iphonesim]; {all solaris systems } systems_solaris = [system_sparc_solaris, system_i386_solaris, @@ -285,7 +286,7 @@ interface systems_objc_supported = systems_darwin; { systems using the non-fragile Objective-C ABI } - systems_objc_nfabi = [system_powerpc64_darwin,system_x86_64_darwin,system_arm_darwin,system_i386_iphonesim]; + systems_objc_nfabi = [system_powerpc64_darwin,system_x86_64_darwin,system_arm_darwin,system_i386_iphonesim,system_aarch64_darwin,system_x86_64_iphonesim]; { all systems supporting exports from programs or units } systems_unit_program_exports = [system_i386_win32, @@ -335,6 +336,10 @@ interface system_jvm_android32 ]; + { all systems where a value parameter passed by reference must be copied + on the caller side rather than on the callee side } + systems_caller_copy_addr_value_para = [system_aarch64_darwin]; + { pointer checking (requires special code in FPC_CHECKPOINTER, and can never work for libc-based targets or any other program linking to an external library) @@ -348,7 +353,8 @@ interface cpu2str : array[TSystemCpu] of string[10] = ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64', - 'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086'); + 'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086', + 'aarch64'); abiinfo : array[tabi] of tabiinfo = ( (name: 'DEFAULT'; supported: true), @@ -357,7 +363,8 @@ interface (name: 'EABI' ; supported:{$ifdef FPC_ARMEL}true{$else}false{$endif}), (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: 'OLDWIN32GNU'; supported:{$ifdef I386}true{$else}false{$endif}), + (name: 'AARCH64IOS'; supported:{$ifdef aarch64}true{$else}false{$endif}) ); var @@ -923,6 +930,21 @@ begin {$ifdef i8086} default_target(system_i8086_msdos); {$endif i8086} + +{$ifdef aarch64} + {$ifdef cpuaarch64} + default_target(source_info.system); + {$else cpuaarch64} + {$ifdef darwin} + {$define default_target_set} + default_target(system_aarch64_darwin); + {$endif darwin} + {$ifndef default_target_set} + default_target(system_aarch64_linux); + {$define default_target_set} + {$endif} + {$endif cpuaarch64} +{$endif aarch64} end; diff --git a/fpcsrc/compiler/systems/i_bsd.pas b/fpcsrc/compiler/systems/i_bsd.pas index 8aafa380..916c6617 100644 --- a/fpcsrc/compiler/systems/i_bsd.pas +++ b/fpcsrc/compiler/systems/i_bsd.pas @@ -952,6 +952,69 @@ unit i_bsd; ); + system_x86_64_iphonesim_info : tsysteminfo = + ( + system : system_x86_64_iphonesim; + name : 'Darwin/iPhoneSim for x86_64'; + shortname : 'iPhoneSim'; + flags : [tf_p_ext_support,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default,tf_has_winlike_resources]; + cpu : cpu_x86_64; + unit_env : 'BSDUNITS'; + extradefines : 'UNIX;BSD;HASUNIX;DARWIN'; // also define darwin for code compatibility + exeext : ''; + defext : '.def'; + scriptext : '.sh'; + smartext : '.sl'; + unitext : '.ppu'; + unitlibext : '.ppl'; + asmext : '.s'; + objext : '.o'; + resext : '.res'; + resobjext : '.or'; + sharedlibext : '.dylib'; + staticlibext : '.a'; + staticlibprefix : 'libp'; + sharedlibprefix : 'lib'; + sharedClibext : '.dylib'; + staticClibext : '.a'; + staticClibprefix : 'lib'; + sharedClibprefix : 'lib'; + importlibprefix : 'libimp'; + importlibext : '.a'; + Cprefix : '_'; + newline : #10; + dirsep : '/'; + assem : as_clang; + assemextern : as_clang; + link : ld_none; + linkextern : ld_bsd; + ar : ar_gnu_ar; + res : res_macho; + dbg : dbg_dwarf2; + script : script_unix; + endian : endian_little; + alignment : + ( + procalign : 8; + loopalign : 4; + jumpalign : 0; + constalignmin : 0; + constalignmax : 8; + varalignmin : 0; + varalignmax : 16; + localalignmin : 4; + localalignmax : 16; + recordalignmin : 0; + recordalignmax : 16; + maxCrecordalign : 16 + ); + first_parm_offset : 16; + stacksize : 262144; + stackalign : 16; + abi : abi_default; + ); + + system_arm_darwin_info : tsysteminfo = ( system : system_arm_darwin; @@ -984,8 +1047,8 @@ unit i_bsd; Cprefix : '_'; newline : #10; dirsep : '/'; - assem : as_darwin; - assemextern : as_darwin; + assem : as_clang; + assemextern : as_clang; link : ld_none; linkextern : ld_bsd; ar : ar_gnu_ar; @@ -1014,6 +1077,71 @@ unit i_bsd; abi : abi_default ); + + system_aarch64_darwin_info : tsysteminfo = + ( + system : system_aarch64_darwin; + name : 'Darwin for AArch64'; + shortname : 'Darwin'; + flags : [tf_p_ext_support,tf_requires_proper_alignment,tf_files_case_sensitive,tf_smartlink_sections,tf_dwarf_relative_addresses,tf_dwarf_only_local_labels,tf_pic_default,tf_has_winlike_resources]; + cpu : cpu_aarch64; + unit_env : 'BSDUNITS'; + extradefines : 'UNIX;BSD;HASUNIX'; + exeext : ''; + defext : '.def'; + scriptext : '.sh'; + smartext : '.sl'; + unitext : '.ppu'; + unitlibext : '.ppl'; + asmext : '.s'; + objext : '.o'; + resext : '.res'; + resobjext : '.or'; + sharedlibext : '.dylib'; + staticlibext : '.a'; + staticlibprefix : 'libp'; + sharedlibprefix : 'lib'; + sharedClibext : '.dylib'; + staticClibext : '.a'; + staticClibprefix : 'lib'; + sharedClibprefix : 'lib'; + importlibprefix : 'libimp'; + importlibext : '.a'; + Cprefix : '_'; + newline : #10; + dirsep : '/'; + assem : as_clang; + assemextern : as_clang; + link : ld_none; + linkextern : ld_bsd; + ar : ar_gnu_ar; + res : res_macho; + dbg : dbg_dwarf2; + script : script_unix; + endian : endian_little; + alignment : + ( + procalign : 8; + loopalign : 4; + jumpalign : 0; + constalignmin : 0; + constalignmax : 8; + varalignmin : 0; + varalignmax : 16; + localalignmin : 4; + localalignmax : 16; + recordalignmin : 0; + recordalignmax : 16; + maxCrecordalign : 16 + ); + first_parm_offset : 16; + stacksize : 8*1024*1024; + stackalign : 16; + abi : abi_aarch64_darwin; + ); + + + implementation initialization @@ -1071,4 +1199,9 @@ initialization set_source_info(system_arm_darwin_info); {$endif Darwin} {$endif cpuarm} +{$ifdef cpuaarch64} + {$ifdef Darwin} + set_source_info(system_aarch64_darwin_info); + {$endif Darwin} +{$endif cpuaarch64} end. diff --git a/fpcsrc/compiler/systems/i_linux.pas b/fpcsrc/compiler/systems/i_linux.pas index 258bf281..6fe97639 100644 --- a/fpcsrc/compiler/systems/i_linux.pas +++ b/fpcsrc/compiler/systems/i_linux.pas @@ -811,6 +811,73 @@ unit i_linux; {$endif FPC_ARMEL} {$endif FPC_ARMHF} + system_aarch64_linux_info : tsysteminfo = + ( + system : system_aarch64_linux; + name : 'Linux for AArch64'; + shortname : 'Linux'; + flags : [tf_needs_symbol_size, + tf_needs_symbol_type, + tf_files_case_sensitive, + tf_requires_proper_alignment, + tf_smartlink_sections,tf_pic_uses_got, + tf_has_winlike_resources]; + cpu : cpu_aarch64; + 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'; + 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 : 0; + constalignmax : 8; + varalignmin : 0; + varalignmax : 16; + localalignmin : 4; + localalignmax : 16; + recordalignmin : 0; + recordalignmax : 16; + maxCrecordalign : 16 + ); + first_parm_offset : 16; + stacksize : 8*1024*1024; + stackalign : 16; + abi : abi_default; + ); + system_mipseb_linux_info : tsysteminfo = ( system : system_mipseb_LINUX; @@ -987,6 +1054,11 @@ initialization set_source_info(system_arm_linux_info); {$endif linux} {$endif CPUARM} +{$ifdef cpuaarch64} + {$ifdef linux} + set_source_info(system_aarch64_linux_info); + {$endif linux} +{$endif cpuaarch64} {$ifdef CPUMIPSEB} {$ifdef linux} set_source_info(system_mipseb_linux_info); diff --git a/fpcsrc/compiler/systems/i_win.pas b/fpcsrc/compiler/systems/i_win.pas index ff73b431..1d2f7838 100644 --- a/fpcsrc/compiler/systems/i_win.pas +++ b/fpcsrc/compiler/systems/i_win.pas @@ -198,7 +198,7 @@ unit i_win; Cprefix : ''; newline : #13#10; dirsep : '\'; - assem : as_gas; + assem : as_arm_pecoffwince; assemextern : as_gas; link : ld_int_windows; linkextern : ld_windows; diff --git a/fpcsrc/compiler/systems/t_bsd.pas b/fpcsrc/compiler/systems/t_bsd.pas index b35a78ae..e4146157 100644 --- a/fpcsrc/compiler/systems/t_bsd.pas +++ b/fpcsrc/compiler/systems/t_bsd.pas @@ -230,28 +230,49 @@ begin begin if not(cs_profile in current_settings.moduleswitches) then begin - { 10.8 and later: no crt1.* } - if CompareVersionStrings(MacOSXVersionMin,'10.8')>=0 then - exit(''); - { x86: crt1.10.6.o -> crt1.10.5.o -> crt1.o } - { others: crt1.10.5 -> crt1.o } -{$if defined(i386) or defined(x86_64)} - if CompareVersionStrings(MacOSXVersionMin,'10.6')>=0 then - exit('crt1.10.6.o'); -{$endif} - if CompareVersionStrings(MacOSXVersionMin,'10.5')>=0 then - exit('crt1.10.5.o'); -{$if defined(arm)} - { iOS: - iOS 6 and later: nothing - iOS 3.1 - 5.x: crt1.3.1.o - pre-iOS 3.1: crt1.o - } - if (CompareVersionStrings(iPhoneOSVersionMin,'6.0')>=0) then - exit(''); - if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then - exit('crt1.3.1.o'); -{$endif} + case target_info.system of + system_powerpc_darwin, + system_powerpc64_darwin, + system_i386_darwin, + system_x86_64_darwin: + begin + { 10.8 and later: no crt1.* } + if CompareVersionStrings(MacOSXVersionMin,'10.8')>=0 then + exit(''); + { x86: crt1.10.6.o -> crt1.10.5.o -> crt1.o } + { others: crt1.10.5 -> crt1.o } + if (target_info.system in [system_i386_darwin,system_x86_64_darwin]) and + (CompareVersionStrings(MacOSXVersionMin,'10.6')>=0) then + exit('crt1.10.6.o'); + if CompareVersionStrings(MacOSXVersionMin,'10.5')>=0 then + exit('crt1.10.5.o'); + end; + system_arm_darwin: + begin + { iOS: + iOS 6 and later: nothing + iOS 3.1 - 5.x: crt1.3.1.o + pre-iOS 3.1: crt1.o + } + if (CompareVersionStrings(iPhoneOSVersionMin,'6.0')>=0) then + exit(''); + if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then + exit('crt1.3.1.o'); + end; + system_i386_iphonesim, + system_x86_64_iphonesim: + begin + { "recent versions" must not use anything (https://github.com/llvm-mirror/clang/commit/e6d04f3d152a22077022cf9287d4c538a0918ab0 ) + What those recent versions could be, is anyone's guess. It + still seems to work with 8.1 and no longer with 8.3, so use + 8.1 as a cut-off point } + if (CompareVersionStrings(iPhoneOSVersionMin,'8.1')>0) then + exit(''); + end; + system_aarch64_darwin: + { never anything } + exit(''); + end; { nothing special -> default } result:='crt1.o'; end @@ -268,34 +289,68 @@ begin begin if (apptype=app_bundle) then begin - { < 10.6: bundle1.o - >= 10.6: nothing } - if CompareVersionStrings(MacOSXVersionMin,'10.6')>=0 then - exit(''); - { iOS: < 3.1: bundle1.o - >= 3.1: nothing } -{$if defined(arm)} - if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then - exit(''); -{$endif} + case target_info.system of + system_powerpc_darwin, + system_powerpc64_darwin, + system_i386_darwin, + system_x86_64_darwin: + begin + { < 10.6: bundle1.o + >= 10.6: nothing } + if CompareVersionStrings(MacOSXVersionMin,'10.6')>=0 then + exit(''); + end; + system_arm_darwin, + system_aarch64_darwin: + begin + { iOS: < 3.1: bundle1.o + >= 3.1: nothing } + if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then + exit(''); + end; + system_i386_iphonesim, + system_x86_64_iphonesim: + begin + { see rule for crt1.o } + if (CompareVersionStrings(iPhoneOSVersionMin,'8.1')>0) then + exit(''); + end; + end; result:='bundle1.o'; end else begin - { >= 10.6: nothing - = 10.5: dylib1.10.5.o - < 10.5: dylib1.o - } - if CompareVersionStrings(MacOSXVersionMin,'10.6')>=0 then - exit(''); - if CompareVersionStrings(MacOSXVersionMin,'10.5')>=0 then - exit('dylib1.10.5.o'); - { iOS: < 3.1: dylib1.o - >= 3.1: nothing } -{$if defined(arm)} - if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then - exit(''); -{$endif} + case target_info.system of + system_powerpc_darwin, + system_powerpc64_darwin, + system_i386_darwin, + system_x86_64_darwin: + begin + { >= 10.6: nothing + = 10.5: dylib1.10.5.o + < 10.5: dylib1.o + } + if CompareVersionStrings(MacOSXVersionMin,'10.6')>=0 then + exit(''); + if CompareVersionStrings(MacOSXVersionMin,'10.5')>=0 then + exit('dylib1.10.5.o'); + end; + system_arm_darwin, + system_aarch64_darwin: + begin + { iOS: < 3.1: dylib1.o + >= 3.1: nothing } + if (CompareVersionStrings(iPhoneOSVersionMin,'3.1')>=0) then + exit(''); + end; + system_i386_iphonesim, + system_x86_64_iphonesim: + begin + { see rule for crt1.o } + if (CompareVersionStrings(iPhoneOSVersionMin,'8.1')>0) then + exit(''); + end; + end; result:='dylib1.o'; end; end; @@ -417,12 +472,17 @@ begin LinkRes.Add('i386'); system_powerpc64_darwin: LinkRes.Add('ppc64'); - system_x86_64_darwin: + system_x86_64_darwin, + system_x86_64_iphonesim: LinkRes.Add('x86_64'); system_arm_darwin: { current versions of the linker require the sub-architecture type to be specified } LinkRes.Add(lower(cputypestr[current_settings.cputype])); + system_aarch64_darwin: + LinkRes.Add('arm64'); + else + internalerror(2014121801); end; if MacOSXVersionMin<>'' then begin @@ -934,6 +994,9 @@ initialization RegisterImport(system_x86_64_darwin,timportlibdarwin); RegisterExport(system_x86_64_darwin,texportlibdarwin); RegisterTarget(system_x86_64_darwin_info); + RegisterImport(system_x86_64_iphonesim,timportlibdarwin); + RegisterExport(system_x86_64_iphonesim,texportlibdarwin); + RegisterTarget(system_x86_64_iphonesim_info); {$endif} {$ifdef i386} RegisterImport(system_i386_freebsd,timportlibbsd); @@ -976,6 +1039,11 @@ initialization RegisterExport(system_arm_darwin,texportlibdarwin); RegisterTarget(system_arm_darwin_info); {$endif arm} +{$ifdef aarch64} + RegisterImport(system_aarch64_darwin,timportlibdarwin); + RegisterExport(system_aarch64_darwin,texportlibdarwin); + RegisterTarget(system_aarch64_darwin_info); +{$endif aarch64} RegisterRes(res_elf_info,TWinLikeResourceFile); RegisterRes(res_macho_info,TWinLikeResourceFile); diff --git a/fpcsrc/compiler/systems/t_linux.pas b/fpcsrc/compiler/systems/t_linux.pas index ed0161c7..0342bc99 100644 --- a/fpcsrc/compiler/systems/t_linux.pas +++ b/fpcsrc/compiler/systems/t_linux.pas @@ -198,6 +198,10 @@ end; {$endif FPC_ARMHF} {$endif arm} +{$ifdef aarch64} +const defdynlinker='/lib/ld-linux-aarch64.so.1'; +{$endif aarch64} + {$ifdef mips} const defdynlinker='/lib/ld.so.1'; {$endif mips} @@ -288,6 +292,7 @@ const {$ifdef POWERPC64} platform_select='-b elf64-powerpc -m elf64ppc';{$endif} {$ifdef sparc} platform_select='-b elf32-sparc -m elf32_sparc';{$endif} {$ifdef arm} platform_select='';{$endif} {unknown :( } +{$ifdef aarch64} platform_select='';{$endif} {unknown :( } {$ifdef m68k} platform_select='';{$endif} {unknown :( } {$ifdef mips} {$ifdef mipsel} @@ -712,6 +717,236 @@ begin add('}'); {$endif x86_64} +{$ifdef AArch64} +{$define LINKERSCRIPT_INCLUDED} + if isdll or (sysrootpath='') then begin + { On other architectures, supplying a complete linker script + without the -T option just results in: + warning: link.res contains output sections; did you forget -T? + However, with a recent aarch64 linker the result is: + /usr/bin/ld: internal error ../../ld/ldlang.c 5221 + So in these cases, where -T will not be used, we supply a + minimal linker script with just the FPC-specific part: } + add('SECTIONS'); + add('{'); + add(' .data :'); + add(' {'); + { extra by FPC } + add(' KEEP (*(.fpc .fpc.n_version .fpc.n_links))'); + add(' }'); + add('}'); + end else begin + { Complete linker script for aarch64-linux: } + add('SECTIONS'); + add('{'); + add(' /* Read-only sections, merged into text segment: */'); + add(' PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;'); + add(' .interp : { *(.interp) }'); + add(' .note.gnu.build-id : { *(.note.gnu.build-id) }'); + add(' .hash : { *(.hash) }'); + add(' .gnu.hash : { *(.gnu.hash) }'); + add(' .dynsym : { *(.dynsym) }'); + add(' .dynstr : { *(.dynstr) }'); + add(' .gnu.version : { *(.gnu.version) }'); + add(' .gnu.version_d : { *(.gnu.version_d) }'); + add(' .gnu.version_r : { *(.gnu.version_r) }'); + add(' .rela.dyn :'); + add(' {'); + add(' *(.rela.init)'); + add(' *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)'); + add(' *(.rela.fini)'); + add(' *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)'); + add(' *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)'); + add(' *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)'); + add(' *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)'); + add(' *(.rela.ctors)'); + add(' *(.rela.dtors)'); + add(' *(.rela.got)'); + add(' *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)'); + add(' *(.rela.ifunc)'); + add(' }'); + add(' .rela.plt :'); + add(' {'); + add(' *(.rela.plt)'); + add(' PROVIDE_HIDDEN (__rela_iplt_start = .);'); + add(' *(.rela.iplt)'); + add(' PROVIDE_HIDDEN (__rela_iplt_end = .);'); + add(' }'); + add(' .init :'); + add(' {'); + add(' KEEP (*(SORT_NONE(.init)))'); + add(' } =0'); + add(' .plt : ALIGN(16) { *(.plt) *(.iplt) }'); + add(' .text :'); + add(' {'); + add(' *(.text.unlikely .text.*_unlikely .text.unlikely.*)'); + add(' *(.text.exit .text.exit.*)'); + add(' *(.text.startup .text.startup.*)'); + add(' *(.text.hot .text.hot.*)'); + add(' *(.text .stub .text.* .gnu.linkonce.t.*)'); + add(' /* .gnu.warning sections are handled specially by elf32.em. */'); + add(' *(.gnu.warning)'); + add(' } =0'); + add(' .fini :'); + add(' {'); + add(' KEEP (*(SORT_NONE(.fini)))'); + add(' } =0'); + add(' PROVIDE (__etext = .);'); + add(' PROVIDE (_etext = .);'); + add(' PROVIDE (etext = .);'); + add(' .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }'); + add(' .rodata1 : { *(.rodata1) }'); + add(' .eh_frame_hdr : { *(.eh_frame_hdr) }'); + add(' .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }'); + add(' .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table'); + add(' .gcc_except_table.*) }'); + add(' /* These sections are generated by the Sun/Oracle C++ compiler. */'); + add(' .exception_ranges : ONLY_IF_RO { *(.exception_ranges'); + add(' .exception_ranges*) }'); + add(' /* Adjust the address for the data segment. We want to adjust up to'); + add(' the same address within the page on the next page up. */'); + add(' . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));'); + add(' /* Exception handling */'); + add(' .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }'); + add(' .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }'); + add(' .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }'); + add(' /* Thread Local Storage sections */'); + add(' .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }'); + add(' .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }'); + add(' .preinit_array :'); + add(' {'); + add(' PROVIDE_HIDDEN (__preinit_array_start = .);'); + add(' KEEP (*(.preinit_array))'); + add(' PROVIDE_HIDDEN (__preinit_array_end = .);'); + add(' }'); + add(' .init_array :'); + add(' {'); + add(' PROVIDE_HIDDEN (__init_array_start = .);'); + add(' KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))'); + add(' KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))'); + add(' PROVIDE_HIDDEN (__init_array_end = .);'); + add(' }'); + add(' .fini_array :'); + add(' {'); + add(' PROVIDE_HIDDEN (__fini_array_start = .);'); + add(' KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))'); + add(' KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))'); + add(' PROVIDE_HIDDEN (__fini_array_end = .);'); + add(' }'); + add(' .ctors :'); + add(' {'); + add(' /* gcc uses crtbegin.o to find the start of'); + add(' the constructors, so we make sure it is'); + add(' first. Because this is a wildcard, it'); + add(' doesn''t matter if the user does not'); + add(' actually link against crtbegin.o; the'); + add(' linker won''t look for a file to match a'); + add(' wildcard. The wildcard also means that it'); + add(' doesn''t matter which directory crtbegin.o'); + add(' is in. */'); + add(' KEEP (*crtbegin.o(.ctors))'); + add(' KEEP (*crtbegin?.o(.ctors))'); + add(' /* We don''t want to include the .ctor section from'); + add(' the crtend.o file until after the sorted ctors.'); + add(' The .ctor section from the crtend file contains the'); + add(' end of ctors marker and it must be last */'); + add(' KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))'); + add(' KEEP (*(SORT(.ctors.*)))'); + add(' KEEP (*(.ctors))'); + add(' }'); + add(' .dtors :'); + add(' {'); + add(' KEEP (*crtbegin.o(.dtors))'); + add(' KEEP (*crtbegin?.o(.dtors))'); + add(' KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))'); + add(' KEEP (*(SORT(.dtors.*)))'); + add(' KEEP (*(.dtors))'); + add(' }'); + add(' .jcr : { KEEP (*(.jcr)) }'); + add(' .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }'); + add(' .dynamic : { *(.dynamic) }'); + add(' .got : { *(.got) *(.igot) }'); + add(' . = DATA_SEGMENT_RELRO_END (24, .);'); + add(' .got.plt : { *(.got.plt) *(.igot.plt) }'); + add(' .data :'); + add(' {'); + add(' PROVIDE (__data_start = .);'); + + { extra by FPC } + add(' KEEP (*(.fpc .fpc.n_version .fpc.n_links))'); + + add(' *(.data .data.* .gnu.linkonce.d.*)'); + add(' SORT(CONSTRUCTORS)'); + add(' }'); + add(' .data1 : { *(.data1) }'); + add(' _edata = .; PROVIDE (edata = .);'); + add(' . = .;'); + add(' __bss_start = .;'); + add(' __bss_start__ = .;'); + add(' .bss :'); + add(' {'); + add(' *(.dynbss)'); + add(' *(.bss .bss.* .gnu.linkonce.b.*)'); + add(' *(COMMON)'); + add(' /* Align here to ensure that the .bss section occupies space up to'); + add(' _end. Align after .bss to ensure correct alignment even if the'); + add(' .bss section disappears because there are no input sections.'); + add(' FIXME: Why do we need it? When there is no .bss section, we don''t'); + add(' pad the .data section. */'); + add(' . = ALIGN(. != 0 ? 64 / 8 : 1);'); + add(' }'); + add(' _bss_end__ = . ; __bss_end__ = . ;'); + add(' . = ALIGN(64 / 8);'); + add(' . = SEGMENT_START("ldata-segment", .);'); + add(' . = ALIGN(64 / 8);'); + add(' __end__ = . ;'); + add(' _end = .; PROVIDE (end = .);'); + add(' . = DATA_SEGMENT_END (.);'); + add(' /* Stabs debugging sections. */'); + add(' .stab 0 : { *(.stab) }'); + add(' .stabstr 0 : { *(.stabstr) }'); + add(' .stab.excl 0 : { *(.stab.excl) }'); + add(' .stab.exclstr 0 : { *(.stab.exclstr) }'); + add(' .stab.index 0 : { *(.stab.index) }'); + add(' .stab.indexstr 0 : { *(.stab.indexstr) }'); + add(' .comment 0 : { *(.comment) }'); + add(' /* DWARF debug sections.'); + add(' Symbols in the DWARF debugging sections are relative to the beginning'); + add(' of the section so we begin them at 0. */'); + add(' /* DWARF 1 */'); + add(' .debug 0 : { *(.debug) }'); + add(' .line 0 : { *(.line) }'); + add(' /* GNU DWARF 1 extensions */'); + add(' .debug_srcinfo 0 : { *(.debug_srcinfo) }'); + add(' .debug_sfnames 0 : { *(.debug_sfnames) }'); + add(' /* DWARF 1.1 and DWARF 2 */'); + add(' .debug_aranges 0 : { *(.debug_aranges) }'); + add(' .debug_pubnames 0 : { *(.debug_pubnames) }'); + add(' /* DWARF 2 */'); + add(' .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }'); + add(' .debug_abbrev 0 : { *(.debug_abbrev) }'); + add(' .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }'); + add(' .debug_frame 0 : { *(.debug_frame) }'); + add(' .debug_str 0 : { *(.debug_str) }'); + add(' .debug_loc 0 : { *(.debug_loc) }'); + add(' .debug_macinfo 0 : { *(.debug_macinfo) }'); + add(' /* SGI/MIPS DWARF 2 extensions */'); + add(' .debug_weaknames 0 : { *(.debug_weaknames) }'); + add(' .debug_funcnames 0 : { *(.debug_funcnames) }'); + add(' .debug_typenames 0 : { *(.debug_typenames) }'); + add(' .debug_varnames 0 : { *(.debug_varnames) }'); + add(' /* DWARF 3 */'); + add(' .debug_pubtypes 0 : { *(.debug_pubtypes) }'); + add(' .debug_ranges 0 : { *(.debug_ranges) }'); + add(' /* DWARF Extension. */'); + add(' .debug_macro 0 : { *(.debug_macro) }'); + add(' .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }'); + add(' .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }'); + add(' /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }'); + add('}'); + end; +{$endif AArch64} + {$ifdef ARM} if target_info.abi in [abi_eabi,abi_eabihf] then begin @@ -1553,6 +1788,11 @@ initialization RegisterExport(system_arm_linux,texportliblinux); RegisterTarget(system_arm_linux_info); {$endif ARM} +{$ifdef aarch64} + RegisterImport(system_aarch64_linux,timportliblinux); + RegisterExport(system_aarch64_linux,texportliblinux); + RegisterTarget(system_aarch64_linux_info); +{$endif aarch64} {$ifdef MIPS} {$ifdef MIPSEL} RegisterImport(system_mipsel_linux,timportliblinux); diff --git a/fpcsrc/compiler/tgobj.pas b/fpcsrc/compiler/tgobj.pas index 6c47ba2a..de49cb6f 100644 --- a/fpcsrc/compiler/tgobj.pas +++ b/fpcsrc/compiler/tgobj.pas @@ -179,7 +179,7 @@ implementation tempfreelist:=nil; templist:=nil; { we could create a new child class for this but I don't if it is worth the effort (FK) } -{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm)} +{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm) or defined(aarch64)} direction:=1; {$else} direction:=-1; diff --git a/fpcsrc/compiler/utils/Makefile.fpc b/fpcsrc/compiler/utils/Makefile.fpc index 9c4ce7ac..2000c78f 100644 --- a/fpcsrc/compiler/utils/Makefile.fpc +++ b/fpcsrc/compiler/utils/Makefile.fpc @@ -3,7 +3,7 @@ # [target] -programs=fpc ppufiles ppudump ppumove mkarmins mkx86ins +programs=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins rst=fpcsubst [clean] diff --git a/fpcsrc/compiler/utils/fpc.pp b/fpcsrc/compiler/utils/fpc.pp index 7da8dd2e..ad79833b 100644 --- a/fpcsrc/compiler/utils/fpc.pp +++ b/fpcsrc/compiler/utils/fpc.pp @@ -143,6 +143,10 @@ program fpc; ppcbin:='ppcarm'; processorname:='arm'; {$endif arm} +{$ifdef aarch64} + ppcbin:='ppca64'; + processorname:='aarch64'; +{$endif arm} {$ifdef sparc} ppcbin:='ppcsparc'; processorname:='sparc'; @@ -202,7 +206,9 @@ program fpc; else if processorstr <> processorname then begin - if processorstr='arm' then + if processorstr='aarch64' then + cpusuffix:='a64' + else if processorstr='arm' then cpusuffix:='arm' else if processorstr='i386' then cpusuffix:='386' diff --git a/fpcsrc/compiler/utils/mka64ins.pp b/fpcsrc/compiler/utils/mka64ins.pp index 4edc87f4..8ac0d109 100644 --- a/fpcsrc/compiler/utils/mka64ins.pp +++ b/fpcsrc/compiler/utils/mka64ins.pp @@ -14,7 +14,7 @@ **********************************************************************} {$mode objfpc} -program mkarmins; +program mka64ins; const Version = '0.9'; @@ -153,7 +153,7 @@ begin writeln('creating ',fn); assign(f,fn); rewrite(f); - writeln(f,'{ don''t edit, this file is generated from armins.dat }'); + writeln(f,'{ don''t edit, this file is generated from a64ins.dat }'); writeln(f,'('); end; diff --git a/fpcsrc/compiler/utils/mkarmins.pp b/fpcsrc/compiler/utils/mkarmins.pp index b8b90671..ad423285 100644 --- a/fpcsrc/compiler/utils/mkarmins.pp +++ b/fpcsrc/compiler/utils/mkarmins.pp @@ -186,7 +186,7 @@ var opcode, codes, flags : string; - optypes : array[1..4] of string; + optypes : array[1..6] of string; begin writeln('Narm Instruction Table Converter Version ',Version); insns:=0; @@ -298,6 +298,8 @@ begin optypes[2]:=''; optypes[3]:=''; optypes[4]:=''; + optypes[5]:=''; + optypes[6]:=''; codes:=''; flags:=''; skip:=false; @@ -324,8 +326,8 @@ begin else break; until false; - for j:=1 to 4-ops do - optypes[4-j+1]:='ot_none'; + for j:=1 to 6-ops do + optypes[6-j+1]:='ot_none'; { codes } skipspace; j:=0; @@ -385,7 +387,7 @@ begin writeln(insfile,' ('); writeln(insfile,' opcode : ',opcode,';'); writeln(insfile,' ops : ',ops,';'); - writeln(insfile,' optypes : (',optypes[1],',',optypes[2],',',optypes[3],',',optypes[4],');'); + writeln(insfile,' optypes : (',optypes[1],',',optypes[2],',',optypes[3],',',optypes[4],',',optypes[5],',',optypes[6],');'); writeln(insfile,' code : ',codes,';'); writeln(insfile,' flags : ',flags); write(insfile,' )'); diff --git a/fpcsrc/compiler/utils/ppuutils/ppudump.pp b/fpcsrc/compiler/utils/ppuutils/ppudump.pp index 0eed7fa1..ae2aef8d 100644 --- a/fpcsrc/compiler/utils/ppuutils/ppudump.pp +++ b/fpcsrc/compiler/utils/ppuutils/ppudump.pp @@ -76,7 +76,8 @@ const { 12 } 'avr', { 13 } 'mipsel', { 14 } 'jvm', - { 15 } 'i8086' + { 15 } 'i8086', + { 16 } 'aarch64' ); { List of all supported system-cpu couples } @@ -109,7 +110,7 @@ const { 24 } 'OpenBSD-i386', { 25 } 'OpenBSD-m68k', { 26 } 'Linux-x86-64', - { 27 } 'MacOSX-ppc', + { 27 } 'Darwin-ppc', { 28 } 'OS/2 via EMX', { 29 } 'NetBSD-powerpc', { 30 } 'OpenBSD-powerpc', @@ -128,7 +129,7 @@ const { 43 } 'Linux-powerpc64', { 44 } 'Darwin-i386', { 45 } 'PalmOS-arm', - { 46 } 'MacOSX-powerpc64', + { 46 } 'Darwin-powerpc64', { 47 } 'NDS-arm', { 48 } 'Embedded-i386', { 49 } 'Embedded-m68k', @@ -143,7 +144,7 @@ const { 58 } 'Embedded-powerpc64', { 59 } 'Symbian-i386', { 60 } 'Symbian-arm', - { 61 } 'MacOSX-x64', + { 61 } 'Darwin-x64', { 62 } 'Embedded-avr', { 63 } 'Haiku-i386', { 64 } 'Darwin-ARM', @@ -167,7 +168,10 @@ const { 82 } 'Embedded-mipsel', { 83 } 'AROS-i386', { 84 } 'AROS-x86-64', - { 85 } 'DragonFly-x86-64' + { 85 } 'DragonFly-x86-64', + { 86 } 'Darwin-AArch64', + { 87 } 'iPhoneSim-x86-64', + { 88 } 'Linux-AArch64' ); const diff --git a/fpcsrc/compiler/version.pas b/fpcsrc/compiler/version.pas index 0e859683..8c7f14a5 100644 --- a/fpcsrc/compiler/version.pas +++ b/fpcsrc/compiler/version.pas @@ -77,6 +77,9 @@ interface {$ifdef cpumipsel} source_cpu_string = 'mipsel'; {$endif cpumipsel} +{$ifdef cpuaarch64} + source_cpu_string = 'aarch64'; +{$endif cpuaarch64} function version_string:string; function full_version_string:string; diff --git a/fpcsrc/compiler/x86/agx86att.pas b/fpcsrc/compiler/x86/agx86att.pas index d3fbdae0..0b5dc2cf 100644 --- a/fpcsrc/compiler/x86/agx86att.pas +++ b/fpcsrc/compiler/x86/agx86att.pas @@ -511,7 +511,7 @@ interface idtxt : 'AS-DARWIN'; asmbin : 'as'; asmcmd : '-o $OBJ $EXTRAOPT $ASM -arch x86_64'; - supported_targets : [system_x86_64_darwin]; + supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim]; flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; labelprefix : 'L'; comment : '# '; @@ -524,7 +524,7 @@ interface idtxt : 'CLANG'; asmbin : 'clang'; asmcmd : '-c -o $OBJ $EXTRAOPT -arch x86_64 $DARWINVERSION -x assembler $ASM'; - supported_targets : [system_x86_64_darwin]; + supported_targets : [system_x86_64_darwin,system_x86_64_iphonesim]; flags : [af_needar,af_smartlink_sections,af_supports_dwarf]; labelprefix : 'L'; comment : '# '; diff --git a/fpcsrc/compiler/x86/cgx86.pas b/fpcsrc/compiler/x86/cgx86.pas index 02a79bbc..74461075 100644 --- a/fpcsrc/compiler/x86/cgx86.pas +++ b/fpcsrc/compiler/x86/cgx86.pas @@ -82,7 +82,7 @@ unit cgx86; procedure a_loadaddr_ref_reg(list : TAsmList;const ref : treference;r : tregister);override; { bit scan instructions } - procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override; + procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); override; { fpu move instructions } procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tcgsize; reg1, reg2: tregister); override; @@ -507,7 +507,7 @@ unit cgx86; end else { Always use RIP relative symbol addressing for Windows and Darwin targets. } - if (target_info.system in (systems_all_windows+[system_x86_64_darwin])) and (ref.base<>NR_RIP) then + if (target_info.system in (systems_all_windows+[system_x86_64_darwin,system_x86_64_iphonesim])) and (ref.base<>NR_RIP) then begin if (ref.refaddr=addr_no) and (ref.base=NR_NO) and (ref.index=NR_NO) then begin @@ -810,7 +810,7 @@ unit cgx86; reference_reset_symbol(r,sym,0,sizeof(pint)); if (cs_create_pic in current_settings.moduleswitches) and { darwin's assembler doesn't want @PLT after call symbols } - not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim]) then + not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim,system_x86_64_iphonesim]) then begin {$ifdef i386} include(current_procinfo.flags,pi_needs_got); @@ -1048,7 +1048,7 @@ unit cgx86; a_op_const_reg(list,OP_ADD,OS_ADDR,offset,r); end {$ifdef x86_64} - else if (target_info.system in (systems_all_windows+[system_x86_64_darwin])) + else if (target_info.system in (systems_all_windows+[system_x86_64_darwin,system_x86_64_iphonesim])) or (cs_create_pic in current_settings.moduleswitches) then begin @@ -2012,20 +2012,36 @@ unit cgx86; end; end; - procedure tcgx86.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); + procedure tcgx86.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: TCGSize; src, dst: TRegister); var + tmpreg: tregister; opsize: topsize; l : TAsmLabel; begin - opsize:=tcgsize2opsize[size]; + { no bsf/bsr for byte } + if srcsize in [OS_8,OS_S8] then + begin + tmpreg:=getintregister(list,OS_INT); + a_load_reg_reg(list,srcsize,OS_INT,src,tmpreg); + src:=tmpreg; + srcsize:=OS_INT; + end; + { source and destination register must have the same size } + if tcgsize2size[srcsize]<>tcgsize2size[dstsize] then + tmpreg:=getintregister(list,srcsize) + else + tmpreg:=dst; + opsize:=tcgsize2opsize[srcsize]; if not reverse then - list.concat(taicpu.op_reg_reg(A_BSF,opsize,src,dst)) + list.concat(taicpu.op_reg_reg(A_BSF,opsize,src,tmpreg)) else - list.concat(taicpu.op_reg_reg(A_BSR,opsize,src,dst)); + list.concat(taicpu.op_reg_reg(A_BSR,opsize,src,tmpreg)); current_asmdata.getjumplabel(l); a_jmp_cond(list,OC_NE,l); - list.concat(taicpu.op_const_reg(A_MOV,opsize,$ff,dst)); + list.concat(taicpu.op_const_reg(A_MOV,opsize,$ff,tmpreg)); a_label(list,l); + if tmpreg<>dst then + a_load_reg_reg(list,srcsize,dstsize,tmpreg,dst); end; {*************** compare instructructions ****************} @@ -2690,7 +2706,8 @@ unit cgx86; a_call_name(list,'MCOUNT',false); end; system_x86_64_linux, - system_x86_64_darwin: + system_x86_64_darwin, + system_x86_64_iphonesim: begin a_call_name(list,'mcount',false); end; @@ -3044,7 +3061,7 @@ unit cgx86; { create pic'ed? } if (cs_create_pic in current_settings.moduleswitches) and { darwin/x86_64's assembler doesn't want @PLT after call symbols } - not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim]) then + not(target_info.system in [system_x86_64_darwin,system_i386_iphonesim,system_x86_64_iphonesim]) then ref.refaddr:=addr_pic else ref.refaddr:=addr_full; diff --git a/fpcsrc/compiler/x86/nx86mem.pas b/fpcsrc/compiler/x86/nx86mem.pas index 40cb3e3b..f4a371e1 100644 --- a/fpcsrc/compiler/x86/nx86mem.pas +++ b/fpcsrc/compiler/x86/nx86mem.pas @@ -27,6 +27,7 @@ interface uses globtype, cgbase,cpuinfo,cpubase, + symtype, node,nmem,ncgmem; type @@ -35,7 +36,7 @@ interface end; tx86vecnode = class(tcgvecnode) - procedure update_reference_reg_mul(maybe_const_reg:tregister;l:aint);override; + procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override; end; implementation @@ -86,7 +87,7 @@ implementation { the live range of the LOC_CREGISTER will most likely overlap the } { the live range of the target LOC_(C)REGISTER) } { The passed register may be a LOC_CREGISTER as well. } - procedure tx86vecnode.update_reference_reg_mul(maybe_const_reg:tregister;l:aint); + procedure tx86vecnode.update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint); var l2 : integer; hreg : tregister; diff --git a/fpcsrc/compiler/x86_64/cgcpu.pas b/fpcsrc/compiler/x86_64/cgcpu.pas index d702844f..8bb4a446 100644 --- a/fpcsrc/compiler/x86_64/cgcpu.pas +++ b/fpcsrc/compiler/x86_64/cgcpu.pas @@ -476,7 +476,7 @@ unit cgcpu; reference_reset_symbol(r,sym,0,sizeof(pint)); if (cs_create_pic in current_settings.moduleswitches) and { darwin/x86_64's assembler doesn't want @PLT after call symbols } - (target_info.system<>system_x86_64_darwin) then + not(target_info.system in systems_darwin) then r.refaddr:=addr_pic else r.refaddr:=addr_full; diff --git a/fpcsrc/compiler/x86_64/cpuelf.pas b/fpcsrc/compiler/x86_64/cpuelf.pas index baaec487..9a3d8d87 100644 --- a/fpcsrc/compiler/x86_64/cpuelf.pas +++ b/fpcsrc/compiler/x86_64/cpuelf.pas @@ -664,6 +664,7 @@ implementation encodereloc: @elf_x86_64_encodeReloc; loadreloc: @elf_x86_64_loadReloc; loadsection: nil; + encodeflags: nil; ); diff --git a/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake b/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake index 0395cb4a..037e5d82 100644 --- a/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake +++ b/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake @@ -13,7 +13,7 @@ units=acceleratorsresource bitmapresource coffconsts coffreader cofftypes \ groupresource icocurtypes machoconsts machoreader machotypes machowriter \ resdatastream resfactory resmerger resource resourcetree resreader reswriter \ stringtableresource strtable tlbreader versionconsts versionresource versiontypes \ - winpeimagereader + winpeimagereader xcoffwriter rsts=versiontypes stringtableresource resource resfactory diff --git a/fpcsrc/packages/fcl-res/src/elfconsts.pp b/fpcsrc/packages/fcl-res/src/elfconsts.pp index 5673950a..1e7b7572 100644 --- a/fpcsrc/packages/fcl-res/src/elfconsts.pp +++ b/fpcsrc/packages/fcl-res/src/elfconsts.pp @@ -22,7 +22,7 @@ interface type TElfMachineType = (emtnone, emtsparc, emti386, emtm68k, emtppc, emtppc64, emtarm, emtarmeb, emtia64, emtx86_64, emtalpha, - emtmips, emtmipsel); + emtmips, emtmipsel, emtaarch64); const ELFMAGIC = chr($7f)+'ELF'; @@ -71,6 +71,7 @@ const EM_IA_64 = 50; EM_MIPS_X = 51; // GNU readelf returns machine name "Stanford MIPS-X" EM_X86_64 = 62; + EM_AARCH64 = 183; EM_ALPHA = $9026; //unofficial, but used by gnu toolchain //machine-specific flags @@ -130,6 +131,7 @@ const R_PPC_ADDR32 = 1; R_PPC64_ADDR64 = 38; R_ARM_ABS32 = 2; + R_AARCH64_ABS64 = 257; R_68K_32 = 1; R_SPARC_32 = 3; R_ALPHA_REFQUAD = 2; diff --git a/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc b/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc index dec11858..aa94e988 100644 --- a/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc +++ b/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc @@ -33,6 +33,9 @@ fMachineType:=emtarmeb; {$ENDIF} {$ENDIF} + {$IFDEF CPUAARCH64} + fMachineType:=emtaarch64; + {$ENDIF} {$IFDEF CPU68K} fMachineType:=emtm68k; {$ENDIF} diff --git a/fpcsrc/packages/fcl-res/src/elfreader.pp b/fpcsrc/packages/fcl-res/src/elfreader.pp index 42159dd5..c6774a6e 100644 --- a/fpcsrc/packages/fcl-res/src/elfreader.pp +++ b/fpcsrc/packages/fcl-res/src/elfreader.pp @@ -282,6 +282,7 @@ begin fMachineType:=emtarm else fMachineType:=emtarmeb; + EM_AARCH64: fMachineType:=emtaarch64; EM_ALPHA : fMachineType:=emtalpha; EM_IA_64 : fMachineType:=emtia64; EM_X86_64 : fMachineType:=emtx86_64; diff --git a/fpcsrc/packages/fcl-res/src/elfsubwriter.inc b/fpcsrc/packages/fcl-res/src/elfsubwriter.inc index 3da0abfe..4a649b5d 100644 --- a/fpcsrc/packages/fcl-res/src/elfsubwriter.inc +++ b/fpcsrc/packages/fcl-res/src/elfsubwriter.inc @@ -27,7 +27,7 @@ type _TElfRelocTable_= class private fList : TFPList; - fRelocType : byte; + fRelocType : longword; fEntrySize : integer; fSectionType : integer; fSectionName : string; @@ -418,6 +418,7 @@ begin EM_386 : begin RelocType:=R_386_32; SectionType:=SHT_REL; end; EM_PPC : begin RelocType:=R_PPC_ADDR32; SectionType:=SHT_RELA; end; EM_ARM : begin RelocType:=R_ARM_ABS32; SectionType:=SHT_REL; end; + EM_AARCH64: begin RelocType:=R_AARCH64_ABS64; SectionType:=SHT_RELA; end; EM_68K : begin RelocType:=R_68K_32; SectionType:=SHT_RELA; end; EM_SPARC : begin RelocType:=R_SPARC_32; SectionType:=SHT_RELA; end; EM_X86_64 : begin RelocType:=R_x86_64_64; SectionType:=SHT_RELA; end; diff --git a/fpcsrc/packages/fcl-res/src/elfwriter.pp b/fpcsrc/packages/fcl-res/src/elfwriter.pp index 1a1e9d2b..eba1e8fe 100644 --- a/fpcsrc/packages/fcl-res/src/elfwriter.pp +++ b/fpcsrc/packages/fcl-res/src/elfwriter.pp @@ -155,7 +155,7 @@ type type TElfRelocInfo = record - RelocType : byte; + RelocType : longword; SectionType : integer; end; (* @@ -551,6 +551,7 @@ begin emtppc64 : begin fMachineTypeInt:=EM_PPC64; fBits:=ELFCLASS64; fOrder:=ELFDATA2MSB; end; emtarm : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2LSB; end; emtarmeb : begin fMachineTypeInt:=EM_ARM; fBits:=ELFCLASS32; fOrder:=ELFDATA2MSB; end; + emtaarch64: begin fMachineTypeInt:=EM_AARCH64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; emtalpha : begin fMachineTypeInt:=EM_ALPHA; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; emtia64 : begin fMachineTypeInt:=EM_IA_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; emtx86_64 : begin fMachineTypeInt:=EM_X86_64; fBits:=ELFCLASS64; fOrder:=ELFDATA2LSB; end; diff --git a/fpcsrc/packages/fcl-res/src/machoconsts.pp b/fpcsrc/packages/fcl-res/src/machoconsts.pp index 7c99421c..b952265e 100644 --- a/fpcsrc/packages/fcl-res/src/machoconsts.pp +++ b/fpcsrc/packages/fcl-res/src/machoconsts.pp @@ -48,6 +48,7 @@ const CPU_TYPE_I386 = 7; CPU_TYPE_X86_64 = CPU_TYPE_I386 or CPU_ARCH_ABI64; CPU_TYPE_ARM = 12; + CPU_TYPE_ARM64 = CPU_TYPE_ARM or CPU_ARCH_ABI64; CPU_TYPE_POWERPC = 18; CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC or CPU_ARCH_ABI64; @@ -61,6 +62,8 @@ const CPU_SUBTYPE_ARM_V5TEJ = 7; CPU_SUBTYPE_ARM_XSCALE = 8; CPU_SUBTYPE_ARM_V7 = 9; + CPU_SUBTYPE_ARM64_ALL = 0; + CPU_SUBTYPE_ARM64_V8 = 1; //Mach-O object types MH_OBJECT = $1; // relocatable object file @@ -180,6 +183,8 @@ const N_SECT = $e; // defined in section number n_sect N_PBUD = $c; // prebound undefined (defined in a dylib) N_INDR = $a; // indirect + + NO_SECT = $0; // symbol is not in any section //Relocations: masks for flag R_SYMBOLNUM_BE = $FFFFFF00; @@ -206,6 +211,9 @@ const // relocation types - ARM ARM_RELOC_VANILLA = 0; // generic relocation + // relocation types - AARCH64 + ARM64_RELOC_UNSIGNED = 0; // for pointers + implementation end. diff --git a/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc b/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc index 66b46a75..c1bc1c4e 100644 --- a/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc +++ b/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc @@ -29,6 +29,9 @@ {$IFDEF CPUARM} fMachineType:=mmtarm; {$ENDIF} + {$IFDEF CPUAARCH64} + fMachineType:=mmtarm64; + {$ENDIF} fBits:=MACH_ERRBIT; {$IFDEF CPU32} diff --git a/fpcsrc/packages/fcl-res/src/machoreader.pp b/fpcsrc/packages/fcl-res/src/machoreader.pp index 17f28e33..7ebd608f 100644 --- a/fpcsrc/packages/fcl-res/src/machoreader.pp +++ b/fpcsrc/packages/fcl-res/src/machoreader.pp @@ -219,7 +219,8 @@ begin CPU_TYPE_X86_64 : fMachineType:=mmtx86_64; CPU_TYPE_POWERPC : fMachineType:=mmtpowerpc; CPU_TYPE_POWERPC64 : fMachineType:=mmtpowerpc64; - CPU_TYPE_ARM : fMachineType:=mmtarm + CPU_TYPE_ARM : fMachineType:=mmtarm; + CPU_TYPE_ARM64 : fMachineType:=mmtarm64 else exit; end; diff --git a/fpcsrc/packages/fcl-res/src/machosubwriter.inc b/fpcsrc/packages/fcl-res/src/machosubwriter.inc index bb1194f0..68287a29 100644 --- a/fpcsrc/packages/fcl-res/src/machosubwriter.inc +++ b/fpcsrc/packages/fcl-res/src/machosubwriter.inc @@ -17,10 +17,11 @@ type _TMachOSymbolTable_ = class(TMachOSymbolTable) protected function AddSymbol(aName : string; sect : byte; addr : longword; - glob : boolean) : integer; override; + glob, undef : boolean) : integer; override; protected public procedure WriteToStream(aStream : TStream); override; + procedure SetSymbolOffset(symbolnum : integer; offset: longword); override; end; _TMachOSubWriter_ = class(TAbstractMachOSubWriter) @@ -34,7 +35,6 @@ type procedure AllocateSpaceForLoadCommands(aStream : TStream); override; procedure FixLoadCommands(aStream : TStream; aResources : TResources); override; - procedure FixResHeader(aStream : TStream); override; public constructor Create(aParent : TMachOResourceWriter; const aMachineType : TMachOMachineType; const aSubMachineType: TMachoSubMachineType; @@ -44,13 +44,17 @@ type { _TMachOSymbolTable_ } function _TMachOSymbolTable_.AddSymbol(aName: string; sect: byte; addr: longword; - glob: boolean): integer; + glob, undef: boolean): integer; var p : _PNlist_; begin p:=GetMem(sizeof(_TNlist_)); p^.strx:=fStringTable.Add(aName); - p^._type:=N_SECT; - if glob then p^._type:=p^._type or N_EXT; + if not undef then + p^._type:=N_SECT + else + p^._type:=N_UNDF; + if glob then + p^._type:=p^._type or N_EXT; p^.desc:=0; p^.sect:=sect; p^.value:=addr; @@ -61,10 +65,20 @@ end; procedure _TMachOSymbolTable_.WriteToStream(aStream: TStream); var nlist : _TNlist_; i : integer; + sawglobal: boolean; begin + { first write local symbols, then global ones, as ilocalsym is hardcoded to + be index 0. Can't reorder here because we may already have used symbol + numbers to generate relocations -> give an error if a global symbol + comes before any local symbols } + sawglobal:=false; for i:=0 to fList.Count-1 do begin nlist:=_PNlist_(fList[i])^; + if (nlist._type and N_EXT)<>0 then + sawglobal:=true + else if sawglobal then + raise EMachOResourceWriterSymbolTableWrongOrderException.Create(''); if fOppositeEndianess then begin nlist.strx:=SwapEndian(nlist.strx); @@ -75,6 +89,14 @@ begin end; end; +procedure _TMachOSymbolTable_.SetSymbolOffset(symbolnum: integer; offset: longword); +var + p : _PNlist_; +begin + p:=_PNlist_(flist[symbolnum]); + p^.value:=offset; +end; + { _TMachOSubWriter_ } procedure _TMachOSubWriter_.SwapSection(var aSection: _TSection_); @@ -109,8 +131,13 @@ begin hdr.count:=aResources.Count; hdr.usedhandles:=0; hdr.handles:=0; - fRelocations.Add(0,1); - fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),2); + { the first pointer (rootptr at offset 0) goes to the root node, which comes + right after the header (the addend has been set to sizeof(hdr) -> add the + address of the fpc.resources section to it via a relocations} + fRelocations.Add(0,ffpcresourcessym); + { the last pointer (handles at offset sizeof(fields before it)) goes to the + fpc.reshandles section } + fRelocations.Add(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles),ffpcreshandlessym); if fOppositeEndianess then begin hdr.rootptr:=SwapEndian(hdr.rootptr); @@ -124,6 +151,7 @@ end; procedure _TMachOSubWriter_.WriteNodeInfos(aStream: TStream); begin + { offset inside the object } fCurOfs:=sizeof(_TResHdr_); WriteNodeInfo(aStream,fRoot); WriteSubNodes(aStream,fRoot); @@ -138,7 +166,7 @@ begin else begin infonode.nameid:=fResStrTable.StartOfs+aNode.NameRVA; - fRelocations.Add(fCurOfs,1); + fRelocations.Add(fCurOfs,ffpcresourcessym); end; infonode.ncount:=aNode.NamedCount; if aNode.IsLeaf then @@ -154,7 +182,7 @@ begin end; fRelocations.Add( fCurOfs+sizeof(infonode.nameid)+sizeof(infonode.ncount)+ - sizeof(infonode.idcountsize),1); + sizeof(infonode.idcountsize),ffpcresourcessym); if fOppositeEndianess then begin infonode.nameid:=SwapEndian(infonode.nameid); @@ -171,7 +199,7 @@ var buf : pbyte; begin fHeader.sizeofcmds:= //segment+res section+bss section - sizeof(_TSegmentCommand_)+sizeof(_TSection_)*2+ + sizeof(_TSegmentCommand_)+sizeof(_TSection_)*3+ //symbol table and dynamic symbol table commands sizeof(TSymtabCommand)+sizeof(TDySymtabCommand)+ //common header of the three commands @@ -190,21 +218,35 @@ var ldcommand : TLoadCommand; segcommand : _TSegmentCommand_; symcommand : TSymtabCommand; dysymcommand : TDySymtabCommand; - ressection,bsssection : _TSection_; + ressection,bsssection,textsection : _TSection_; begin ldcommand.cmd:=fSegType; - ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*2; + ldcommand.cmdsize:=sizeof(TLoadCommand)+sizeof(segcommand)+sizeof(ressection)*3; FillByte(segcommand.name[0],16,0); segcommand.vmaddr:=0; segcommand.vmsize:=fDataCurOfs+sizeof(_ptrtype_)*aResources.Count; segcommand.fileoff:=fSectionStart; segcommand.filesize:=fDataCurOfs; - segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE; - segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE; - segcommand.nsects:=2; + segcommand.maxprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE; + segcommand.initprot:=VM_PROT_READ or VM_PROT_WRITE or VM_PROT_EXECUTE; + segcommand.nsects:=3; segcommand.flags:=0; + fillbyte(textsection,sizeof(textsection),0); + textsection.sectname:='__text'; + textsection.segname:='__TEXT'; + textsection.addr:=0; + textsection.size:=0; + textsection.offset:=segcommand.fileoff; + textsection.align:=0; + textsection.reloff:=0; + textsection.nreloc:=0; + textsection.flags:=S_ATTR_PURE_INSTRUCTIONS; + textsection.reserved1:=0; + textsection.reserved2:=0; + + fillbyte(ressection,sizeof(ressection),0); ressection.sectname:=RsrcSectName; ressection.segname:=DataSegName; ressection.addr:=0; @@ -217,6 +259,7 @@ begin ressection.reserved1:=0; ressection.reserved2:=0; + fillbyte(bsssection,sizeof(bsssection),0); bsssection.sectname:=HandlesSectName; bsssection.segname:=DataSegName; bsssection.addr:=fDataCurOfs; @@ -243,12 +286,14 @@ begin segcommand.nsects:=SwapEndian(segcommand.nsects); segcommand.flags:=SwapEndian(segcommand.flags); + SwapSection(textsection); SwapSection(ressection); SwapSection(bsssection); end; aStream.WriteBuffer(ldcommand,sizeof(ldcommand)); aStream.WriteBuffer(segcommand,sizeof(segcommand)); + aStream.WriteBuffer(textsection,sizeof(textsection)); aStream.WriteBuffer(ressection,sizeof(ressection)); aStream.WriteBuffer(bsssection,sizeof(bsssection)); @@ -258,7 +303,7 @@ begin symcommand.symoff:=fSymbolTable.StartOfs; symcommand.nsyms:=fSymbolTable.Count; symcommand.stroff:=fMachOStringTable.StartOfs; - symcommand.strsize:=NextAligned(fDataAlignment,fMachOStringTable.Size); + symcommand.strsize:=NextAligned(4,fMachOStringTable.Size); if fOppositeEndianess then begin @@ -325,17 +370,6 @@ begin aStream.WriteBuffer(dysymcommand,sizeof(dysymcommand)); end; -procedure _TMachOSubWriter_.FixResHeader(aStream : TStream); -var hdr : _TResHdr_; -begin - hdr.handles:=fDataCurOfs; - if fOppositeEndianess then - hdr.handles:=SwapEndian(hdr.handles); - aStream.Seek(sizeof(hdr.rootptr)+sizeof(hdr.count)+sizeof(hdr.usedhandles), - soFromCurrent); - aStream.WriteBuffer(hdr.handles,sizeof(hdr.handles)); -end; - constructor _TMachOSubWriter_.Create(aParent : TMachOResourceWriter; const aMachineType : TMachOMachineType; const aSubMachineType: TMachoSubMachineType; const aOppositeEndianess : boolean); begin diff --git a/fpcsrc/packages/fcl-res/src/machotypes.pp b/fpcsrc/packages/fcl-res/src/machotypes.pp index ec5288d6..0feb0c1e 100644 --- a/fpcsrc/packages/fcl-res/src/machotypes.pp +++ b/fpcsrc/packages/fcl-res/src/machotypes.pp @@ -19,17 +19,20 @@ unit machotypes; interface +{$packrecords c} + type - TMachOMachineType = (mmtpowerpc, mmtpowerpc64, mmti386, mmtx86_64, mmtarm); + TMachOMachineType = (mmtpowerpc, mmtpowerpc64, mmti386, mmtx86_64, mmtarm, mmtarm64); TMachOSubMachineTypePowerPC = (msmppc_all); TMachOSubMachineTypePowerPC64 = (msmppc64_all); TMachOSubMachineType386 = (msm386_all); TMachOSubMachineTypex64 = (msmx64_all); TMachOSubMachineTypeArm = (msmarm_all,msmarm_v4t,msmarm_v6,msmarm_v5tej,msmarm_xscale,msmarm_v7); + TMachOSubMachineTypeAarch64 = (msmaarch64_all); TSegSectName = array[0..15] of char; type - TMachHdr = packed record + TMachHdr = record magic : longword; cputype : longint; cpusubtype : longint; @@ -39,14 +42,14 @@ type flags : longword; end; - TLoadCommand = packed record + TLoadCommand = record cmd : longword; cmdsize : longword; end; //note: all commands don't include first two longwords - TSegmentCommand32 = packed record + TSegmentCommand32 = record name : TSegSectName; vmaddr : longword; vmsize : longword; @@ -58,7 +61,7 @@ type flags : longword; end; - TSegmentCommand64 = packed record + TSegmentCommand64 = record name : TSegSectName; vmaddr : qword; vmsize : qword; @@ -70,7 +73,7 @@ type flags : longword; end; - TSection32 = packed record + TSection32 = record sectname : TSegSectName; segname : TSegSectName; addr : longword; @@ -84,7 +87,7 @@ type reserved2 : longword; end; - TSection64 = packed record + TSection64 = record sectname : TSegSectName; segname : TSegSectName; addr : qword; @@ -99,14 +102,14 @@ type reserved3 : longword; end; - TSymtabCommand = packed record + TSymtabCommand = record symoff : longword; nsyms : longword; stroff : longword; strsize : longword; end; - TDySymtabCommand = packed record + TDySymtabCommand = record ilocalsym : longword; nlocalsym : longword; iextdefsym : longword; @@ -127,7 +130,7 @@ type nlocrel : longword; end; - TNList32 = packed record + TNList32 = record strx : longword; _type : byte; sect : byte; @@ -136,7 +139,7 @@ type end; PNList32 = ^TNList32; - TNList64 = packed record + TNList64 = record strx : longword; _type : byte; sect : byte; @@ -145,7 +148,7 @@ type end; PNList64 = ^TNList64; - TRelocationInfo = packed record + TRelocationInfo = record address : longword; flags : longword; end; diff --git a/fpcsrc/packages/fcl-res/src/machowriter.pp b/fpcsrc/packages/fcl-res/src/machowriter.pp index 3b7946b1..3fc3f700 100644 --- a/fpcsrc/packages/fcl-res/src/machowriter.pp +++ b/fpcsrc/packages/fcl-res/src/machowriter.pp @@ -25,6 +25,7 @@ uses type EMachOResourceWriterException = class(EResourceWriterException); EMachOResourceWriterUnknownBitSizeException = class(EMachOResourceWriterException); + EMachOResourceWriterSymbolTableWrongOrderException = class(EMachOResourceWriterException); type @@ -37,6 +38,7 @@ type msm386_all: (f386SubType: TMachOSubMachineType386); msmx64_all: (fX64SubType: TMachOSubMachineTypex64); mmtarm: (fArmSubType: TMachOSubMachineTypeArm); + mmtarm64: (fArm64SubType: TMachOSubMachineTypeAarch64); end; TMachOResourceWriter = class(TAbstractResourceWriter) @@ -85,7 +87,7 @@ type public constructor Create(aMachineType : TMachOMachineType; aOppositeEndianess : boolean); destructor Destroy; override; - procedure Add(addr : longword; sectnum : longword); + procedure Add(addr: longword; symnum: longword); procedure Clear; procedure WriteToStream(aStream : TStream); property Count : integer read GetCount; @@ -104,15 +106,17 @@ type fOppositeEndianess : boolean; function GetCount : integer; function AddSymbol(aName : string; sect : byte; addr : longword; - glob : boolean) : integer; virtual; abstract; + glob, undef : boolean) : integer; virtual; abstract; protected public constructor Create(aStringTable : TObjectStringTable); destructor Destroy; override; - function AddLocal(aName : string; sect : byte; addr : longword) : integer; - function AddGlobal(aName : string; sect : byte; addr : longword) : integer; + function AddLocal(const aName : string; sect : byte; addr : longword) : integer; + function AddGlobal(const aName : string; sect : byte; addr : longword) : integer; + function AddExternal(const aName : string) : integer; procedure Clear; procedure WriteToStream(aStream : TStream); virtual; abstract; + procedure SetSymbolOffset(symbolnum : integer; offset: longword); virtual; abstract; property Count : integer read GetCount; property LocalCount : integer read fLocalCount; property GlobalCount : integer read fGlobalCount; @@ -140,6 +144,8 @@ type fCurOfs : longword; fDataCurOfs : longword; fSectionStart : longword; + ffpcresourcessym, + ffpcreshandlessym : integer; function NextAligned(aBound, aValue : longword) : longword; procedure Align(aBound : integer; aStream : TStream); @@ -240,17 +246,23 @@ begin fList.Free; end; -function TMachOSymbolTable.AddLocal(aName: string; sect: byte; addr: longword +function TMachOSymbolTable.AddLocal(const aName: string; sect: byte; addr: longword ): integer; begin - Result:=AddSymbol(aName,sect,addr,false); + Result:=AddSymbol(aName,sect,addr,false,false); inc(fLocalCount); end; -function TMachOSymbolTable.AddGlobal(aName: string; sect: byte; addr: longword +function TMachOSymbolTable.AddGlobal(const aName: string; sect: byte; addr: longword ): integer; begin - Result:=AddSymbol(aName,sect,addr,true); + Result:=AddSymbol(aName,sect,addr,true,false); + inc(fGlobalCount); +end; + +function TMachOSymbolTable.AddExternal(const aName: string): integer; +begin + Result:=AddSymbol(aName,NO_SECT,0,false,true); inc(fGlobalCount); end; @@ -301,6 +313,11 @@ begin fRelocType:=ARM_RELOC_VANILLA; fRelocSize:=2; end; + mmtarm64 : begin + fEndianess:=MACH_LITTLE_ENDIAN; + fRelocType:=ARM64_RELOC_UNSIGNED; + fRelocSize:=3; + end; end; fOppositeEndianess:=aOppositeEndianess; end; @@ -311,7 +328,7 @@ begin fList.Free; end; -procedure TMachORelocations.Add(addr: longword; sectnum: longword); +procedure TMachORelocations.Add(addr: longword; symnum: longword); var p : PRelocationInfo; begin p:=GetMem(sizeof(TRelocationInfo)); @@ -319,15 +336,19 @@ begin //bit fields make things difficult... if fEndianess=MACH_BIG_ENDIAN then begin - p^.flags:=sectnum shl 8; + p^.flags:=symnum shl 8; p^.flags:=p^.flags or (fRelocSize shl 5); //length p^.flags:=p^.flags or fRelocType; + { reference via symbol } + p^.flags:=p^.flags or R_EXTERN_BE; end else begin - p^.flags:=sectnum and R_SYMBOLNUM_LE; + p^.flags:=symnum and R_SYMBOLNUM_LE; p^.flags:=p^.flags or (fRelocSize shl 25); //length p^.flags:=p^.flags or (fRelocType shl 28); + { reference via symbol } + p^.flags:=p^.flags or R_EXTERN_LE; end; fList.Add(p); end; @@ -491,6 +512,7 @@ const armsm2int: array[TMachOSubMachineTypeArm] of longint = (CPU_SUBTYPE_ARM_ALL, CPU_SUBTYPE_ARM_V4T,CPU_SUBTYPE_ARM_V6,CPU_SUBTYPE_ARM_V5TEJ, CPU_SUBTYPE_ARM_XSCALE,CPU_SUBTYPE_ARM_V7); + arm64sm2int: array[TMachOSubMachineTypeAarch64] of longint = (CPU_SUBTYPE_ARM64_ALL); begin aStream.Position:=0; case fMachineType of @@ -519,6 +541,11 @@ begin fHeader.cputype:=CPU_TYPE_ARM; fHeader.cpusubtype:=armsm2int[fSubMachineType.fArmSubType]; end; + mmtarm64 : begin + fHeader.magic:=MH_MAGIC_64; + fHeader.cputype:=CPU_TYPE_ARM64; + fHeader.cpusubtype:=arm64sm2int[fSubMachineType.fArm64SubType]; + end; end; fHeader.filetype:=MH_OBJECT; fHeader.ncmds:=3; @@ -544,22 +571,39 @@ begin AllocateSpaceForLoadCommands(aStream); fSectionStart:=aStream.Position; fRoot:=TRootResTreeNode(fParent.GetTree(aResources)); + { on AArch64, if you want to refer to a section from another one, you + have to do it via an explicit symbol reference. + + } + { dummy text section symbol } + fSymbolTable.AddLocal('ltmp0',1,0); + { dummy fpc.resources symbol } + fSymbolTable.AddLocal('ltmp1',2,0); + { the offset needs to be the offset in the file, *not* relative to the start + of the section. We don't know here yet how large the fpcresources section + will be -> fix up later } + ffpcreshandlessym:=fSymbolTable.AddGlobal('__fpc_reshandles_internal',3,0); + { don't add this before any local symbols, as local symbols must be written + first. We can't reorder while writing the symbol table, because we already + need the symbol numbers above } + ffpcresourcessym:=fSymbolTable.AddGlobal('FPC_RESSYMBOL',2,0); + PrescanResourceTree; WriteResHeader(aStream,aResources); WriteNodeInfos(aStream); WriteResStringTable(aStream); WriteRawData(aStream); -// fSymbolTable.AddGlobal('FPCRES_SECTION',1,0); - fSymbolTable.AddGlobal('FPC_RESSYMBOL',1,0); fRelocations.StartOfs:=aStream.Position; WriteRelocations(aStream); + + { fix up offset of fpcreshandles symbol } + fSymbolTable.SetSymbolOffset(ffpcreshandlessym,fDataCurOfs); fSymbolTable.StartOfs:=aStream.Position; WriteSymbolTable(aStream); fMachOStringTable.StartOfs:=aStream.Position; WriteMachOStringTable(aStream); FixHeader(aStream); FixLoadCommands(aStream,aResources); - FixResHeader(aStream); end; constructor TAbstractMachOSubWriter.Create(aParent : TMachOResourceWriter; @@ -602,6 +646,7 @@ begin mmti386 : begin fBits:=MACH_32BIT; fEndianess:=MACH_LITTLE_ENDIAN; end; mmtx86_64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_LITTLE_ENDIAN; end; mmtarm : begin fBits:=MACH_32BIT; fEndianess:=MACH_LITTLE_ENDIAN; end; + mmtarm64 : begin fBits:=MACH_64BIT; fEndianess:=MACH_LITTLE_ENDIAN; end; end; fMachineType:=aMachineType; fOppositeEndianess:=fNativeEndianess<>fEndianess; diff --git a/fpcsrc/packages/fpmkunit/src/fpmkunit.pp b/fpcsrc/packages/fpmkunit/src/fpmkunit.pp index 35b5fb61..1938f2aa 100644 --- a/fpcsrc/packages/fpmkunit/src/fpmkunit.pp +++ b/fpcsrc/packages/fpmkunit/src/fpmkunit.pp @@ -110,7 +110,7 @@ Type // Please keep this order, see OSCPUSupported below TCpu=(cpuNone, i386,m68k,powerpc,sparc,x86_64,arm,powerpc64,avr,armeb, - mips,mipsel,jvm,i8086 + mips,mipsel,jvm,i8086,aarch64 ); TCPUS = Set of TCPU; @@ -184,45 +184,45 @@ Const { This table is kept OS,Cpu because it is easier to maintain (PFV) } OSCPUSupported : array[TOS,TCpu] of boolean = ( - { os none i386 m68k ppc sparc x86_64 arm ppc64 avr armeb mips mipsel jvm i8086} - { none } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { linux } ( false, true, true, true, true, true, true, true, false, true , true , true , false, false), - { go32v2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { win32 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { os2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { freebsd } ( false, true, true, false, false, true, false, false, false, false, false, false, false, false), - { beos } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { netbsd } ( false, true, true, true, true, true, false, false, false, false, false, false, false, false), - { amiga } ( false, false, true, true, false, false, false, false, false, false, false, false, false, false), - { atari } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false), - { solaris } ( false, true, false, false, true, true, false, false, false, false, false, false, false, false), - { qnx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { netware } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { openbsd } ( false, true, true, false, false, true, false, false, false, false, false, false, false, false), - { wdosx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { palmos } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false), - { macos } ( false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { darwin } ( false, true, false, true, false, true, true, true, false, false, false, false, false, false), - { emx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { watcom } ( false, true, false, false, false ,false, false, false, false, false, false, false, false, false), - { morphos } ( false, false, false, true, false ,false, false, false, false, false, false, false, false, false), - { netwlibc }( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { win64 } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false), - { wince }( false, true, false, false, false, false, true, false, false, false, false, false, false, false), - { gba } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false), - { nds } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false), - { embedded }( false, true, true, true, true, true, true, true, true, true , false, false, false, false), - { symbian } ( false, true, false, false, false, false, true, false, false, false, false, false, false, false), - { haiku } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { iphonesim}( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { aix } ( false, false, false, true, false, false, false, true, false, false, false, false, false, false), - { java } ( false, false, false, false, false, false, false, false, false, false, false, false, true , false), - { android } ( false, true, false, false, false, false, true, false, false, false, false, true, true , false), - { nativent }( false, true, false, false, false, false, false, false, false, false, false, false, false, false), - { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, true ), - { wii } ( false, false, false, true , false, false, false, false, false, false, false, false, false, false), - { aros } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { dragonfly}( false, false, false, false, false, true, false, false, false, false, false, false, false, false ) + { os none i386 m68k ppc sparc x86_64 arm ppc64 avr armeb mips mipsel jvm i8086 aarch64 } + { none } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { linux } ( false, true, true, true, true, true, true, true, false, true , true , true , false, false, true ), + { go32v2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win32 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { os2 } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { freebsd } ( false, true, true, false, false, true, false, false, false, false, false, false, false, false, false), + { beos } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netbsd } ( false, true, true, true, true, true, false, false, false, false, false, false, false, false, false), + { amiga } ( false, false, true, true, false, false, false, false, false, false, false, false, false, false, false), + { atari } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), + { solaris } ( false, true, false, false, true, true, false, false, false, false, false, false, false, false, false), + { qnx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netware } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { openbsd } ( false, true, true, false, false, true, false, false, false, false, false, false, false, false, false), + { wdosx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { palmos } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false), + { macos } ( false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { darwin } ( false, true, false, true, false, true, true, true, false, false, false, false, false, false, true ), + { emx } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { watcom } ( false, true, false, false, false ,false, false, false, false, false, false, false, false, false, false), + { morphos } ( false, false, false, true, false ,false, false, false, false, false, false, false, false, false, false), + { netwlibc }( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win64 } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false), + { wince }( false, true, false, false, false, false, true, false, false, false, false, false, false, false, false), + { gba } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false), + { nds } ( false, false, false, false, false, false, true, false, false, false, false, false, false, false, false), + { embedded }( false, true, true, true, true, true, true, true, true, true , false, false, false, false, false), + { symbian } ( false, true, false, false, false, false, true, false, false, false, false, false, false, false, false), + { haiku } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { iphonesim}( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false), + { aix } ( false, false, false, true, false, false, false, true, false, false, false, false, false, false, false), + { java } ( false, false, false, false, false, false, false, false, false, false, false, false, true , false, false), + { android } ( false, true, false, false, false, false, true, false, false, false, false, true, true , false, false), + { nativent }( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), + { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, true , false), + { wii } ( false, false, false, true , false, false, false, false, false, false, false, false, false, false, false), + { aros } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { dragonfly}( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false) ); // Useful @@ -2645,6 +2645,7 @@ begin x86_64: result := GetGccDirArch('cpux86_64','-m64'); powerpc: result := GetGccDirArch('cpupowerpc','-m32'); powerpc64:result := GetGccDirArch('cpupowerpc64','-m64'); + aarch64: result := GetGccDirArch('cpuaarch64',''); end {case} else if OS = darwin then case CPU of @@ -2652,6 +2653,8 @@ begin x86_64: result := GetGccDirArch('cpux86_64','-arch x86_64'); powerpc: result := GetGccDirArch('cpupowerpc','-arch ppc'); powerpc64:result := GetGccDirArch('cpupowerpc64','-arch ppc64'); + { this target uses clang } + aarch64: result := '' end; {case} end; diff --git a/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake b/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake index 72aeea63..14f3a8cf 100644 --- a/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake +++ b/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake @@ -7,7 +7,7 @@ name=univint version=3.0.4 [target] -units=iosxlocale +units=iosxlocale iosxwstr [libs] libversion=2.0.0 diff --git a/fpcsrc/packages/iosxlocale/fpmake.pp b/fpcsrc/packages/iosxlocale/fpmake.pp index d123c233..95533965 100644 --- a/fpcsrc/packages/iosxlocale/fpmake.pp +++ b/fpcsrc/packages/iosxlocale/fpmake.pp @@ -22,6 +22,7 @@ begin P.OSes:=[darwin,iphonesim]; T:=P.Targets.AddUnit('iosxlocale.pp'); + T:=P.Targets.AddUnit('iosxwstr.pp'); {$ifndef ALLPACKAGES} Run; diff --git a/fpcsrc/packages/iosxlocale/src/iosxwstr.pp b/fpcsrc/packages/iosxlocale/src/iosxwstr.pp new file mode 100644 index 00000000..cdbc31f3 --- /dev/null +++ b/fpcsrc/packages/iosxlocale/src/iosxwstr.pp @@ -0,0 +1,665 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2015 by Jonas Maebe, + member of the Free Pascal development team. + + CoreFoundation-based wide string support + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + **********************************************************************} + +{$mode objfpc} +{$implicitexceptions off} + +unit iosxwstr; + +interface + +{$linkframework CoreFoundation} + + procedure SetCFWidestringManager; + +implementation + + uses + unixcp, + { for access to libiconv-based routines } + cwstring, + MacTypes, + CFBase,CFString,CFStringEncodingExt,CFLocale; + + procedure fpc_rangeerror; [external name 'FPC_RANGEERROR']; + + var + CWStringWideStringManager: TUnicodeStringManager; + + procedure InitThread; + begin + { we don't need anything special, but since we may use cwstring itself, + call through to it } + CWStringWideStringManager.ThreadInitProc; + end; + + + procedure FiniThread; + begin + { we don't need anything special, but since we may use cwstring itself, + call through to it } + CWStringWideStringManager.ThreadFiniProc; + end; + + + function get_cfencoding_for_cp(cp: TSystemCodePage): CFStringEncoding; + var + defscp: TSystemCodePage; + begin + { translate placeholder code pages } + if (cp=CP_ACP) or + (cp=CP_OEMCP) then + cp:=DefaultSystemCodePage; + result:=CFStringConvertWindowsCodepageToEncoding(cp); + end; + + + procedure GetAnsiDataFromCFString(str: CFstringRef; cfcp: CFStringEncoding; estimated_length: SizeInt; var dest: RawByteString); + var + range: CFRange; + encodedlen,convertedchars: CFIndex; + strlen: SizeInt; + begin + { first rough estimate for the length } + setlength(dest,estimated_length); + { try to convert } + range.location:=0; + strlen:=CFStringGetLength(str); + range.length:=strlen; + convertedchars:=CFStringGetBytes(str,range,cfcp,ByteParameter('?'),false,UInt8Ptr(dest),estimated_length,encodedlen); + { failed -> bail out } + if convertedchars<0 then + begin + CFRelease(str); + runerror(231); + end + { if partially succesful, recreate with the required len } + else if convertedcharsstrlen then + begin + CFRelease(str); + runerror(231); + end; + end; + { truncate } + setlength(dest,encodedlen); + end; + + + function CFStringCreateFromAnsiData(data: pchar; len: SizeInt; cp: TSystemCodePage): CFStringRef; + var + strlen,encodedlen: CFIndex; + range: CFRange; + cfcp: CFStringEncoding; + begin + result:=nil; + { get source cf codepage } + cfcp:=get_cfencoding_for_cp(cp); + { unsupported encoding -> try libiconv instead } + if cfcp=kCFStringEncodingInvalidId then + exit; + { make a cfstring from the original data } + result:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(data),len,cfcp,false,kCFAllocatorNull); + end; + + + function CFStringCreateFromAnsiDataOptionallyViaUnicodeString(data: pchar; len: SizeInt; cp: TSystemCodePage; out wtemp: UnicodeString): CFStringRef; + begin + result:=CFStringCreateFromAnsiData(data,len,cp); + { failed -> translate via libiconv and then create using the unicodestring + characters; since we use the no-copy constructor for performance + reasons, the unicodestring has to survive this routine } + if not assigned(result) then + begin + CWStringWideStringManager.Ansi2UnicodeMoveProc(data,cp,wtemp,len); + result:=CFStringCreateWithCharactersNoCopy(nil,UniCharPtr(wtemp),len,kCFAllocatorNull); + end; + end; + + + function CFStringCreateFromWideData(data: pwidechar; len: SizeInt): CFStringRef; inline; + begin + { make a cfstring from the utf-16 data } + result:=CFStringCreateWithCharactersNoCopy(nil,UniCharPtr(data),len,kCFAllocatorNull); + end; + + + function CFStringCreateFromWideDataOptionallyViaUUTF8String(data: pwidechar; len: SizeInt; out temp: RawByteString): CFStringRef; + begin + result:=CFStringCreateFromWideData(data,len); + { failed -> translate to UTF-8 via libiconv to filter out any + potentially invalid characters and then create using the unicodestring + characters; since we use the no-copy constructor for performance + reasons, the unicodestring has to survive this routine } + if not assigned(result) then + begin + CWStringWideStringManager.Unicode2AnsiMoveProc(data,temp,CP_UTF8,len); + result:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(temp),length(temp),kCFStringEncodingUTF8,false,kCFAllocatorNull); + if not assigned(result) then + runerror(231) + end; + end; + + + procedure Wide2AnsiMove(source:pwidechar; var dest:RawByteString; cp:TSystemCodePage; len:SizeInt); + var + str: CFStringRef; + strlen,estimatedlen: CFIndex; + cfcp: CFStringEncoding; + begin + str:=nil; + { get target cf codepage } + cfcp:=get_cfencoding_for_cp(cp); + { unsupported encoding -> default move } + if cfcp<>kCFStringEncodingInvalidId then + { make a cfstring from the utf-16 data } + str:=CFStringCreateFromWideData(source,len); + { You cannot create a CFString for a sequence that contains an error :/ + We want to replace the error positions with '?' -> fall back to libiconv + } + if not assigned(str) then + begin + CWStringWideStringManager.Unicode2AnsiMoveProc(source,dest,cp,len); + exit; + end; + + GetAnsiDataFromCFString(str,cfcp,len*3,dest); + { set code page } + SetCodePage(dest,cp,false); + { release cfstring } + CFRelease(str); + end; + + + procedure Ansi2WideMove(source:pchar; cp:TSystemCodePage; var dest:widestring; len:SizeInt); + var + str: CFStringRef; + strlen,encodedlen: CFIndex; + range: CFRange; + cfcp: CFStringEncoding; + begin + str:=CFStringCreateFromAnsiData(source,len,cp); + { You cannot create a CFString for a sequence that contains an error :/ + We want to replace the error positions with '?' -> fall back to libiconv + } + if not assigned(str) then + begin + CWStringWideStringManager.Ansi2UnicodeMoveProc(source,cp,dest,len); + exit; + end; + + { convert } + range.location:=0; + strlen:=CFStringGetLength(str); + range.length:=strlen; + setlength(dest,strlen); + CFStringGetCharacters(str,range,UniCharPtr(dest)); + { release cfstring } + CFRelease(str); + end; + + + function LowerWideString(const s : WideString) : WideString; + var + str: CFStringRef; + mstr: CFMutableStringRef; + range: CFRange; + encodedlen: CFIndex; + locale: CFLocaleRef; + temp: RawByteString; + begin + { empty string -> exit } + if s='' then + begin + result:=''; + exit; + end; + { create cfstring from the string data } + str:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s),length(s),temp); + { convert to mutable cfstring } + mstr:=CFStringCreateMutableCopy(nil,0,str); + { lowercase } + locale:=CFLocaleCopyCurrent; + CFStringLowercase(mstr,locale); + CFRelease(locale); + { extract the data again } + range.location:=0; + range.length:=CFStringGetLength(CFStringRef(mstr)); + setlength(result,range.length); + CFStringGetCharacters(mstr,range,UniCharPtr(result)); + CFRelease(mstr); + CFRelease(str); + end; + + + function UpperWideString(const s : WideString) : WideString; + var + str: CFStringRef; + mstr: CFMutableStringRef; + range: CFRange; + encodedlen: CFIndex; + locale: CFLocaleRef; + temp: RawByteString; + begin + { empty string -> exit } + if s='' then + begin + result:=''; + exit; + end; + { create cfstring from the string data } + str:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s),length(s),temp); + { convert to mutable cfstring } + mstr:=CFStringCreateMutableCopy(nil,0,str); + { lowercase } + locale:=CFLocaleCopyCurrent; + CFStringUppercase(mstr,locale); + CFRelease(locale); + { extract the data again } + range.location:=0; + range.length:=CFStringGetLength(CFStringRef(mstr)); + setlength(result,range.length); + CFStringGetCharacters(mstr,range,UniCharPtr(result)); + CFRelease(mstr); + CFRelease(str); + end; + + + function UpperLowerAnsiString(const s: AnsiString; upper: boolean): AnsiString; + var + str: CFStringRef; + mstr: CFMutableStringRef; + cfcp: CFStringEncoding; + locale: CFLocaleRef; + wtemp: UnicodeString; + range: CFRange; + begin + if s='' then + begin + result:=''; + exit + end; + str:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(pchar(s),length(s),StringCodePage(s),wtemp); + { unsupported encoding for either CF or iconv -> return original string } + if not assigned(str) then + begin + result:=s; + exit; + end; + { convert to mutable cfstring } + mstr:=CFStringCreateMutableCopy(nil,0,str); + CFRelease(str); + { upper/lowercase } + locale:=CFLocaleCopyCurrent; + if upper then + CFStringUppercase(mstr,locale) + else + CFStringLowercase(mstr,locale); + CFRelease(locale); + { convert back to ansistring } + cfcp:=get_cfencoding_for_cp(StringCodePage(s)); + if cfcp<>kCFStringEncodingInvalidId then + begin + GetAnsiDataFromCFString(CFStringRef(mstr),cfcp,length(s),RawByteString(result)); + SetCodePage(RawByteString(result),StringCodePage(s),false); + end + else + begin + { unsupported encoding -> use libiconv instead via UTF-16 + intermediate } + range.location:=0; + range.length:=CFStringGetLength(mstr); + SetLength(wtemp,range.length); + CFStringGetCharacters(mstr,range,UniCharPtr(wtemp)); + CWStringWideStringManager.Wide2AnsiMoveProc(pwidechar(wtemp),RawByteString(result),StringCodePage(s),range.length); + end; + CFRelease(mstr); + end; + + + function LowerAnsiString(const s: AnsiString): AnsiString; + begin + result:=UpperLowerAnsiString(s,false); + end; + + + function UpperAnsiString(const s: AnsiString): AnsiString; + begin + result:=UpperLowerAnsiString(s,true); + end; + + + function CompareCFStrings(const s1, s2: CFStringRef; case_insensitive: boolean): longint; + var + flags: CFStringCompareFlags; + begin + flags:=0; + if case_insensitive then + flags:=flags or kCFCompareCaseInsensitive; + result:=CFStringCompare(s1,s2,flags) + end; + + + function CompareWideString(const s1, s2 : WideString) : PtrInt; + var + cfstr1, cfstr2: CFStringRef; + temp1, temp2: RawByteString; + begin + cfstr1:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s1),length(s1),temp1); + cfstr2:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s2),length(s2),temp2); + result:=CompareCFStrings(cfstr1,cfstr2,false); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + function CompareTextWideString(const s1, s2 : WideString): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + temp1, temp2: RawByteString; + begin + cfstr1:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s1),length(s1),temp1); + cfstr2:=CFStringCreateFromWideDataOptionallyViaUUTF8String(pwidechar(s2),length(s2),temp2); + result:=CompareCFStrings(cfstr1,cfstr2,true); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function InternalCodePointLength(const Str: PChar; cfcp: CFStringEncoding; maxlookahead: ptrint): PtrInt; + var + cfstr: CFStringRef; + begin + result:=0; + { try creating a string with the first 1, 2, ... bytes until we find a + valid one } + while (str[result]<>#0) and + (result skip } + if tmplen=-1 then + tmplen:=1; + inc(s,tmplen); + inc(result); + until s[0]=#0; + end; + + + function CodePointLength(const Str: PChar; maxlookahead: ptrint): PtrInt; + var + cfstr: CFStringRef; + cfcp: CFStringEncoding; + begin + result:=0; + if str[0]=#0 then + exit; + cfcp:=get_cfencoding_for_cp(DefaultSystemCodePage); + if cfcp=kCFStringEncodingInvalidId then + begin + { if we would return -1, then the caller would keep trying with + longer and longer sequences, but that wouldn't change anything } + result:=1; + exit + end; + result:=InternalCodePointLength(str,cfcp,maxlookahead); + end; + + + function CompareStrAnsiString(const s1, s2: ansistring): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(pchar(s1),length(s1),StringCodePage(s1),wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(pchar(s2),length(s2),StringCodePage(s2),wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,false); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function StrCompAnsi(s1,s2 : PChar): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,strlen(s1),DefaultSystemCodePage,wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,strlen(s2),DefaultSystemCodePage,wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,false); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function AnsiCompareText(const S1, S2: ansistring): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(pchar(s1),length(s1),DefaultSystemCodePage,wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(pchar(s2),length(s2),DefaultSystemCodePage,wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,true); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function AnsiStrIComp(S1, S2: PChar): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,strlen(s1),DefaultSystemCodePage,wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,strlen(s2),DefaultSystemCodePage,wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,true); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function AnsiStrLComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,MaxLen,StringCodePage(s1),wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,MaxLen,StringCodePage(s2),wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,false); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + function AnsiStrLIComp(S1, S2: PChar; MaxLen: PtrUInt): PtrInt; + var + cfstr1, cfstr2: CFStringRef; + wtemp1, wtemp2: UnicodeString; + begin + cfstr1:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s1,MaxLen,StringCodePage(s1),wtemp1); + cfstr2:=CFStringCreateFromAnsiDataOptionallyViaUnicodeString(s2,MaxLen,StringCodePage(s2),wtemp2); + result:=CompareCFStrings(cfstr1,cfstr2,true); + CFRelease(cfstr1); + CFRelease(cfstr2); + end; + + + procedure ansi2pchar(const s: ansistring; const orgp: pchar; out p: pchar); + var + newlen: sizeint; + begin + newlen:=length(s); + if newlen>strlen(orgp) then + fpc_rangeerror; + p:=orgp; + if (newlen>0) then + move(s[1],p[0],newlen); + p[newlen]:=#0; + end; + + + function AnsiStrLower(Str: PChar): PChar; + var + temp: ansistring; + begin + temp:=loweransistring(str); + ansi2pchar(temp,str,result); + end; + + + function AnsiStrUpper(Str: PChar): PChar; + var + temp: ansistring; + begin + temp:=upperansistring(str); + ansi2pchar(temp,str,result); + end; + + + function GetStandardCodePage(const stdcp: TStandardCodePageEnum): TSystemCodePage; + var + langinfo: pchar; + begin + { don't use CFStringGetSystemEncoding, that one returns MacRoman on e.g. + an English system, which is definitely not what we want. Since there are + no "ansi" interfaces on OS X and all APIs support all characters, always + use UTF-8. Additionally,  Darwin always uses UTF-8 for file system + operations } + result:=CP_UTF8; + end; + + + procedure SetStdIOCodePage(var T: Text); inline; + begin + case TextRec(T).Mode of + fmInput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleInput); + fmOutput:TextRec(T).CodePage:=GetStandardCodePage(scpConsoleOutput); + end; + end; + + + procedure SetStdIOCodePages; inline; + begin + SetStdIOCodePage(Input); + SetStdIOCodePage(Output); + SetStdIOCodePage(ErrOutput); + SetStdIOCodePage(StdOut); + SetStdIOCodePage(StdErr); + end; + + + procedure SetCFWideStringManager; + var + CFWideStringManager : TUnicodeStringManager; + begin + GetUnicodeStringManager(CWStringWideStringManager); + CFWideStringManager:=CWStringWideStringManager; + with CFWideStringManager do + begin + Wide2AnsiMoveProc:=@Wide2AnsiMove; + Ansi2WideMoveProc:=@Ansi2WideMove; + + UpperWideStringProc:=@UpperWideString; + LowerWideStringProc:=@LowerWideString; + + CompareWideStringProc:=@CompareWideString; + CompareTextWideStringProc:=@CompareTextWideString; + + CharLengthPCharProc:=@CharLengthPChar; + CodePointLengthProc:=@CodePointLength; + + UpperAnsiStringProc:=@UpperAnsiString; + LowerAnsiStringProc:=@LowerAnsiString; + CompareStrAnsiStringProc:=@CompareStrAnsiString; + CompareTextAnsiStringProc:=@AnsiCompareText; + StrCompAnsiStringProc:=@StrCompAnsi; + StrICompAnsiStringProc:=@AnsiStrIComp; + StrLCompAnsiStringProc:=@AnsiStrLComp; + StrLICompAnsiStringProc:=@AnsiStrLIComp; + StrLowerAnsiStringProc:=@AnsiStrLower; + StrUpperAnsiStringProc:=@AnsiStrUpper; + ThreadInitProc:=@InitThread; + ThreadFiniProc:=@FiniThread; + { Unicode } + Unicode2AnsiMoveProc:=@Wide2AnsiMove; + Ansi2UnicodeMoveProc:=@Ansi2WideMove; + UpperUnicodeStringProc:=@UpperWideString; + LowerUnicodeStringProc:=@LowerWideString; + CompareUnicodeStringProc:=@CompareWideString; + CompareTextUnicodeStringProc:=@CompareTextWideString; + { CodePage } + GetStandardCodePageProc:=@GetStandardCodePage; + end; + SetUnicodeStringManager(CFWideStringManager); + end; + + +initialization + SetCFWideStringManager; + + { set the DefaultSystemCodePage } + DefaultSystemCodePage:=GetStandardCodePage(scpAnsi); + DefaultFileSystemCodePage:=GetStandardCodePage(scpFileSystemSingleByte); + DefaultRTLFileSystemCodePage:=DefaultFileSystemCodePage; + + SetStdIOCodePages; + + { don't call init, we don't need to do anything and the cwstring routine we + call through has already been called from the init code of cwstring itself + InitThread; + } +finalization + { don't call for the same reason as not calling FiniThread + FiniThread; + } + { restore previous widestring manager so that subsequent calls + into the widestring manager won't trigger the finalized functionality } + SetWideStringManager(CWStringWideStringManager); +end. diff --git a/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc b/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc index 32fb02b3..c20586f6 100644 --- a/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc +++ b/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc @@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. } -{$if not defined(cpux86_64) and not defined(NO_SYSCALL_SOCKETCALL)} +{$if not defined(cpux86_64) and not defined(cpuaarch64) and not defined(NO_SYSCALL_SOCKETCALL)} {$define NEED_SOCKETCALL} {$endif} diff --git a/fpcsrc/packages/rtl-extra/src/unix/ipc.pp b/fpcsrc/packages/rtl-extra/src/unix/ipc.pp index 597e5de6..fbccd250 100644 --- a/fpcsrc/packages/rtl-extra/src/unix/ipc.pp +++ b/fpcsrc/packages/rtl-extra/src/unix/ipc.pp @@ -876,7 +876,7 @@ uses Syscall; {$ifndef FPC_USE_LIBC} {$if defined(Linux)} - {$if defined(cpux86_64) or defined(NO_SYSCALL_IPC)} + {$if defined(cpux86_64) or defined(cpuaarch64) or defined(NO_SYSCALL_IPC)} {$i ipcsys.inc} {$else} {$i ipccall.inc} diff --git a/fpcsrc/rtl/aarch64/aarch64.inc b/fpcsrc/rtl/aarch64/aarch64.inc new file mode 100644 index 00000000..38b51ff0 --- /dev/null +++ b/fpcsrc/rtl/aarch64/aarch64.inc @@ -0,0 +1,322 @@ +{ + + This file is part of the Free Pascal run time library. + Copyright (c) 2014 by Jonas Maebe, member of + the Free Pascal development team. + + Processor dependent implementation for the system unit for + AArch64 + + 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. + + **********************************************************************} + +{$IFNDEF LINUX} + {$DEFINE USE_DCBZ} +{$ENDIF LINUX} + +{**************************************************************************** + AArch64 specific stuff +****************************************************************************} +const + fpu_ioe = 1 shl 8; + fpu_dze = 1 shl 9; + fpu_ofe = 1 shl 10; + fpu_ufe = 1 shl 11; + fpu_ixe = 1 shl 12; + fpu_ide = 1 shl 15; + fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide; + fpu_exception_mask_to_status_mask_shift = 8; + +function getfpcr: dword; nostackframe; assembler; + asm + mrs x0,fpcr + end; + + +procedure setfpcr(val: dword); nostackframe; assembler; + asm + msr fpcr,x0 + end; + + +function getfpsr: dword; nostackframe; assembler; + asm + mrs x0,fpsr + end; + + +procedure setfpsr(val: dword); nostackframe; assembler; + asm + msr fpsr, x0 + end; + + +procedure fpc_enable_fpu_exceptions; + begin + { clear all "exception happened" flags we care about} + setfpsr(getfpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift)); + { enable invalid operations and division by zero exceptions. } + setfpcr(getfpcr or fpu_exception_mask); + end; + +procedure fpc_cpuinit; + begin + { don't let libraries influence the FPU cw set by the host program } + if not IsLibrary then + fpc_enable_fpu_exceptions; + end; + + +{**************************************************************************** + Move / Fill +****************************************************************************} + + +{**************************************************************************** + String +****************************************************************************} + +{$define FPC_SYSTEM_HAS_GET_CALLER_ADDR} +function get_caller_addr(framebp:pointer;addr:pointer=nil):pointer;assembler; nostackframe; + asm + cbz x0, .Lcaller_addr_invalid + ldur x0, [x0] + cbz x0, .Lcaller_addr_invalid + ldur x0, [x0, #8] + .Lcaller_addr_invalid: + end; + + +{$define FPC_SYSTEM_HAS_GET_CALLER_FRAME} +function get_caller_frame(framebp:pointer;addr:pointer=nil):pointer;assembler; nostackframe; + asm + cbz x0, .Lcaller_addr_invalid + ldur x0, [x0] + .Lcaller_addr_invalid: + end; + + +{$define FPC_SYSTEM_HAS_SPTR} +Function Sptr : Pointer;assembler; nostackframe; + asm + mov x0, sp + end; + + +{**************************************************************************** + Str() +****************************************************************************} + +{ int_str: generic implementation is used for now } + + +{**************************************************************************** + Multithreading +****************************************************************************} + +{ perform a thread-safe inc/dec } + +{$define FPC_SYSTEM_HAS_DECLOCKED_LONGINT} +function declocked(var l : longint) : boolean;assembler;nostackframe; + { input: address of l in x0 } + { output: boolean indicating whether l is zero after decrementing } + asm + .LDecLockedLoop: + ldxr w1,[x0] + sub w1,w1,#1 + stxr w2,w1,[x0] + cbnz w2,.LDecLockedLoop + cset w0, eq + end; + + +{$define FPC_SYSTEM_HAS_INCLOCKED_LONGINT} +procedure inclocked(var l : longint);assembler;nostackframe; + asm + .LIncLockedLoop: + ldxr w1,[x0] + add w1,w1,#1 + stxr w2,w1,[x0] + cbnz w2,.LIncLockedLoop + end; + + +{$define FPC_SYSTEM_HAS_DECLOCKED_INT64} +function declocked(var l : int64) : boolean;assembler;nostackframe; + { input: address of l in x0 } + { output: boolean indicating whether l is zero after decrementing } + asm + .LDecLockedLoop: + ldxr x1,[x0] + subs x1,x1,#1 + stxr w2,x1,[x0] + cbnz w2,.LDecLockedLoop + cset w0, eq + end; + + +{$define FPC_SYSTEM_HAS_INCLOCKED_INT64} +procedure inclocked(var l : int64);assembler;nostackframe; + asm + .LIncLockedLoop: + ldxr x1,[x0] + add x1,x1,#1 + stxr w2,x1,[x0] + cbnz w2,.LIncLockedLoop + end; + + +function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe; + { input: address of target in x0 } + { output: target-1 in x0 } + { side-effect: target := target-1 } + asm + .LInterDecLockedLoop: + ldxr w1,[x0] + sub w1,w1,#1 + stxr w2,w1,[x0] + cbnz w2,.LInterDecLockedLoop + mov w0,w1 + end; + + +function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe; + { input: address of target in x0 } + { output: target+1 in x0 } + { side-effect: target := target+1 } + asm + .LInterIncLockedLoop: + ldxr w1,[x0] + add w1,w1,#1 + stxr w2,w1,[x0] + cbnz w2,.LInterIncLockedLoop + mov w0,w1 + end; + + +function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe; + { input: address of target in x0, source in w1 } + { output: target in x0 } + { side-effect: target := source } + asm + .LInterLockedXchgLoop: + ldxr w2,[x0] + stxr w3,w1,[x0] + cbnz w3,.LInterLockedXchgLoop + mov w0,w2 + end; + + +function InterLockedExchangeAdd (var Target: longint;Source : longint) : longint; assembler; nostackframe; + asm + .LInterLockedXchgAddLoop: + ldxr w2,[x0] + add w4,w2,w1 + stxr w3,w4,[x0] + cbnz w3,.LInterLockedXchgAddLoop + mov w0,w2 + end; + + +function InterlockedCompareExchange(var Target: longint; NewValue: longint; Comperand: longint): longint; assembler; nostackframe; + { input: address of target in x0, newvalue in w1, comparand in w2 } + { output: value stored in target before entry of the function } + { side-effect: NewValue stored in target if (target = comparand) } + asm + .LInterlockedCompareExchangeLoop: + ldxr w3,[x0] + cmp w3,w2 + csel w4,w1,w3,eq + stxr w5,w4,[x0] + cbnz w5,.LInterlockedCompareExchangeLoop + mov w0,w3 + end; + + +function InterLockedDecrement64 (var Target: int64) : int64; assembler; nostackframe; + asm + .LInterDecLockedLoop: + ldxr x1,[x0] + sub x1,x1,#1 + stxr w2,x1,[x0] + cbnz w2,.LInterDecLockedLoop + mov x0,x1 + end; + + +function InterLockedIncrement64 (var Target: int64) : int64; assembler; nostackframe; + asm + .LInterIncLockedLoop: + ldxr x1,[x0] + add x1,x1,#1 + stxr w2,x1,[x0] + cbnz w2,.LInterIncLockedLoop + mov x0,x1 + end; + + +function InterLockedExchange64 (var Target: int64;Source : int64) : int64; assembler; nostackframe; + asm + .LInterLockedXchgLoop: + ldxr x2,[x0] + stxr w3,x1,[x0] + cbnz w3,.LInterLockedXchgLoop + mov x0,x2 + end; + + +function InterLockedExchangeAdd64 (var Target: int64;Source : int64) : int64; assembler; nostackframe; + asm + .LInterLockedXchgAddLoop: + ldxr x2,[x0] + add x4,x2,x1 + stxr w3,x4,[x0] + cbnz w3,.LInterLockedXchgAddLoop + mov x0,x2 + end; + + +function InterLockedCompareExchange64(var Target: int64; NewValue, Comperand : int64): int64; assembler; nostackframe; + asm + .LInterlockedCompareExchangeLoop: + ldxr x3,[x0] + cmp x3,x2 + csel x4,x1,x3,eq + stxr w5,x4,[x0] + cbnz w5,.LInterlockedCompareExchangeLoop + mov x0,x3 + end; + + +{$ifndef FPC_SYSTEM_HAS_MEM_BARRIER} +{$define FPC_SYSTEM_HAS_MEM_BARRIER} +procedure ReadBarrier;assembler;nostackframe;{$ifdef SYSTEMINLINE}inline;{$endif} + asm + { dmb ishld } + dmb #9 + end; + +procedure ReadDependencyBarrier;{$ifdef SYSTEMINLINE}inline;{$endif} +begin + { reads imply barrier on earlier reads depended on } +end; + +procedure ReadWriteBarrier;assembler;nostackframe;{$ifdef SYSTEMINLINE}inline;{$endif} +asm + { dmb ish } + dmb #11 +end; + +procedure WriteBarrier;assembler;nostackframe;{$ifdef SYSTEMINLINE}inline;{$endif} +asm + { dmb ishst } + dmb #10 +end; + +{$endif} diff --git a/fpcsrc/rtl/aarch64/int64p.inc b/fpcsrc/rtl/aarch64/int64p.inc new file mode 100644 index 00000000..4a18e168 --- /dev/null +++ b/fpcsrc/rtl/aarch64/int64p.inc @@ -0,0 +1,15 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by the Free Pascal development team + + This file contains some helper routines for int64 and qword + + 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. + + **********************************************************************} +{ only dummy on AArch64 since it has a 64 bit integer unit } diff --git a/fpcsrc/rtl/aarch64/makefile.cpu b/fpcsrc/rtl/aarch64/makefile.cpu new file mode 100644 index 00000000..d380a265 --- /dev/null +++ b/fpcsrc/rtl/aarch64/makefile.cpu @@ -0,0 +1,7 @@ +# +# Here we set processor dependent include file names. +# + +CPUNAMES=aarch64 int64p math set setjump setjumph strings stringss +CPUINCNAMES=$(addsuffix .inc,$(CPUNAMES)) +# diff --git a/fpcsrc/rtl/aarch64/math.inc b/fpcsrc/rtl/aarch64/math.inc new file mode 100644 index 00000000..99e8efbd --- /dev/null +++ b/fpcsrc/rtl/aarch64/math.inc @@ -0,0 +1,86 @@ +{ + Implementation of mathematical routines for x86_64 + + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2005 by the Free Pascal development team + + 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. + + **********************************************************************} + + +{**************************************************************************** + Floating point type routines + ****************************************************************************} + + {$ifndef FPC_SYSTEM_HAS_ABS} + {$define FPC_SYSTEM_HAS_ABS} + function fpc_abs_real(d : ValReal) : ValReal;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; + end; + {$endif FPC_SYSTEM_HAS_ABS} + + + {$ifndef FPC_SYSTEM_HAS_SQR} + {$define FPC_SYSTEM_HAS_SQR} + function fpc_sqr_real(d : ValReal) : ValReal;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; + end; + {$endif FPC_SYSTEM_HAS_SQR} + + + {$ifndef FPC_SYSTEM_HAS_SQRT} + {$define FPC_SYSTEM_HAS_SQRT} + function fpc_sqrt_real(d : ValReal) : ValReal;compilerproc; + begin + { Function is handled internal in the compiler } + runerror(207); + result:=0; + end; + {$endif FPC_SYSTEM_HAS_SQRT} + + + {$ifndef FPC_SYSTEM_HAS_INT} + {$define FPC_SYSTEM_HAS_INT} + function fpc_int_real(d : ValReal) : ValReal;assembler;nostackframe;compilerproc; + asm + { round as floating point towards zero } + frintz d0,d0 + end; + {$endif FPC_SYSTEM_HAS_INT} + + + {$ifndef FPC_SYSTEM_HAS_TRUNC} + {$define FPC_SYSTEM_HAS_TRUNC} + function fpc_trunc_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; + asm + { round to signed integer towards zero } + fcvtzs x0,d0 + end; + {$endif FPC_SYSTEM_HAS_TRUNC} + + + {$ifndef FPC_SYSTEM_HAS_ROUND} + {$define FPC_SYSTEM_HAS_ROUND} + function fpc_round_real(d : ValReal) : int64;assembler;nostackframe;compilerproc; + asm + { round as floating point using current rounding mode } + frintx d0,d0 + { convert to signed integer rounding towards zero (there's no "round to + integer using current rounding mode") } + fcvtzs x0,d0 + end; + {$endif FPC_SYSTEM_HAS_ROUND} + + diff --git a/fpcsrc/rtl/aarch64/mathu.inc b/fpcsrc/rtl/aarch64/mathu.inc new file mode 100644 index 00000000..dacd3db5 --- /dev/null +++ b/fpcsrc/rtl/aarch64/mathu.inc @@ -0,0 +1,157 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2014 by Jonas Maebe + member of the Free Pascal development team + + 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. + +**********************************************************************} + +{$asmmode gas} + +function getfpcr: dword; nostackframe; assembler; + asm + mrs x0,fpcr + end; + + +procedure setfpcr(val: dword); nostackframe; assembler; + asm + msr fpcr,x0 + end; + + +function getfpsr: dword; nostackframe; assembler; + asm + mrs x0,fpsr + end; + + +procedure setfpsr(val: dword); nostackframe; assembler; + asm + msr fpsr, x0 + end; + + +function GetRoundMode: TFPURoundingMode; + const + bits2rm: array[0..3] of TFPURoundingMode = (rmNearest,rmUp,rmDown,rmTruncate); + begin + result:=TFPURoundingMode(bits2rm[(getfpcr shr 22) and 3]) + end; + + +function SetRoundMode(const RoundMode: TFPURoundingMode): TFPURoundingMode; + const + rm2bits: array[TFPURoundingMode] of byte = (0,2,1,3); + begin + softfloat_rounding_mode:=RoundMode; + SetRoundMode:=RoundMode; + setfpcr((getfpcr and $ff3fffff) or (rm2bits[RoundMode] shl 22)); + end; + + +function GetPrecisionMode: TFPUPrecisionMode; + begin + result:=pmDouble; + end; + + +function SetPrecisionMode(const Precision: TFPUPrecisionMode): TFPUPrecisionMode; + begin + result:=pmDouble; + end; + + +const + fpu_ioe = 1 shl 8; + fpu_dze = 1 shl 9; + fpu_ofe = 1 shl 10; + fpu_ufe = 1 shl 11; + fpu_ixe = 1 shl 12; + fpu_ide = 1 shl 15; + fpu_exception_mask = fpu_ioe or fpu_dze or fpu_ofe or fpu_ufe or fpu_ixe or fpu_ide; + fpu_exception_mask_to_status_mask_shift = 8; + + +function GetExceptionMask: TFPUExceptionMask; + var + fpcr: dword; + begin + fpcr:=getfpcr; + result:=[]; + if ((fpcr and fpu_ioe)=0) then + result := result+[exInvalidOp]; + if ((fpcr and fpu_ofe)=0) then + result := result+[exOverflow]; + if ((fpcr and fpu_ufe)=0) then + result := result+[exUnderflow]; + if ((fpcr and fpu_dze)=0) then + result := result+[exZeroDivide]; + if ((fpcr and fpu_ixe)=0) then + result := result+[exPrecision]; + if ((fpcr and fpu_ide)=0) then + result := result+[exDenormalized]; + end; + + +function SetExceptionMask(const Mask: TFPUExceptionMask): TFPUExceptionMask; + var + newfpcr: dword; + begin + softfloat_exception_mask:=mask; + newfpcr:=fpu_exception_mask; + if exInvalidOp in Mask then + newfpcr:=newfpcr and not(fpu_ioe); + if exOverflow in Mask then + newfpcr:=newfpcr and not(fpu_ofe); + if exUnderflow in Mask then + newfpcr:=newfpcr and not(fpu_ufe); + if exZeroDivide in Mask then + newfpcr:=newfpcr and not(fpu_dze); + if exPrecision in Mask then + newfpcr:=newfpcr and not(fpu_ixe); + if exDenormalized in Mask then + newfpcr:=newfpcr and not(fpu_ide); + { clear "exception happened" flags } + ClearExceptions(false); + { set new exception mask } + setfpcr((getfpcr and not(fpu_exception_mask)) or newfpcr); + { unsupported mask bits will remain 0 -> read exception mask again } + result:=GetExceptionMask; + softfloat_exception_mask:=result; + end; + + +procedure ClearExceptions(RaisePending: Boolean); + var + fpsr: dword; + f: TFPUException; + begin + fpsr:=getfpsr; + if raisepending then + begin + if (fpsr and (fpu_dze shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exZeroDivide); + if (fpsr and (fpu_ofe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exOverflow); + if (fpsr and (fpu_ufe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exUnderflow); + if (fpsr and (fpu_ioe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exInvalidOp); + if (fpsr and (fpu_ixe shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exPrecision); + if (fpsr and (fpu_ide shr fpu_exception_mask_to_status_mask_shift)) <> 0 then + float_raise(exDenormalized); + { now the soft float exceptions } + for f in softfloat_exception_flags do + float_raise(f); + end; + softfloat_exception_flags:=[]; + setfpsr(fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift)); + end; diff --git a/fpcsrc/rtl/aarch64/set.inc b/fpcsrc/rtl/aarch64/set.inc new file mode 100644 index 00000000..af93168b --- /dev/null +++ b/fpcsrc/rtl/aarch64/set.inc @@ -0,0 +1,15 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2002 by the Free Pascal development team + + Include file with set operations called by the compiler + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + diff --git a/fpcsrc/rtl/aarch64/setjump.inc b/fpcsrc/rtl/aarch64/setjump.inc new file mode 100644 index 00000000..db4e7a7a --- /dev/null +++ b/fpcsrc/rtl/aarch64/setjump.inc @@ -0,0 +1,59 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2015 by Jonas Maebe and other members of the + Free Pascal development team + + SetJmp/Longjmp implementation for AArch64 + + 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. + + + **********************************************************************} + +function fpc_setjmp(var S: jmp_buf): longint; assembler; [public, alias:'FPC_SETJMP']; nostackframe; compilerproc; + asm + mov x3, sp + stp x19, x20, [x0, #jmp_buf.x19] + stp x21, x22, [x0, #jmp_buf.x21] + stp x23, x24, [x0, #jmp_buf.x23] + stp x25, x26, [x0, #jmp_buf.x25] + stp x27, x28, [x0, #jmp_buf.x27] + stp x29, x30, [x0, #jmp_buf.x29] + str x3, [x0, #jmp_buf.xsp] + + stp d8, d9, [x0, #jmp_buf.d8] + stp d10, d11, [x0, #jmp_buf.d10] + stp d12, d13, [x0, #jmp_buf.d12] + stp d14, d15, [x0, #jmp_buf.d14] + + mov x0, xzr + end; + + +procedure fpc_longjmp(var S: jmp_buf ;value: longint); assembler; [public, alias:'FPC_LONGJMP']; nostackframe; compilerproc; + asm + ldr x3, [x0, #jmp_buf.xsp] + + ldp x19, x20, [x0, #jmp_buf.x19] + ldp x21, x22, [x0, #jmp_buf.x21] + ldp x23, x24, [x0, #jmp_buf.x23] + ldp x25, x26, [x0, #jmp_buf.x25] + ldp x27, x28, [x0, #jmp_buf.x27] + ldp x29, x30, [x0, #jmp_buf.x29] + + mov sp, x3 + + ldp d8, d9, [x0, #jmp_buf.d8] + ldp d10, d11, [x0, #jmp_buf.d10] + ldp d12, d13, [x0, #jmp_buf.d12] + ldp d14, d15, [x0, #jmp_buf.d14] + + mov x0, x1 + end; + + diff --git a/fpcsrc/rtl/aarch64/setjumph.inc b/fpcsrc/rtl/aarch64/setjumph.inc new file mode 100644 index 00000000..81436cd4 --- /dev/null +++ b/fpcsrc/rtl/aarch64/setjumph.inc @@ -0,0 +1,45 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2000-2002 by Jonas Maebe and other members of the + Free Pascal development team + + SetJmp/Longjmp declarations + + 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. + + **********************************************************************} + +type + jmp_buf = record + x19: qword; + x20: qword; + x21: qword; + x22: qword; + x23: qword; + x24: qword; + x25: qword; + x26: qword; + x27: qword; + x28: qword; + x29: qword; + x30: qword; + xsp: qword; + d8: qword; + d9: qword; + d10: qword; + d11: qword; + d12: qword; + d13: qword; + d14: qword; + d15: qword; + end; + pjmp_buf = ^jmp_buf; + +function setjmp(var S : jmp_buf) : longint;[external name 'FPC_SETJMP']; +procedure longjmp(var S : jmp_buf;value : longint);[external name 'FPC_LONGJMP']; + diff --git a/fpcsrc/rtl/aarch64/strings.inc b/fpcsrc/rtl/aarch64/strings.inc new file mode 100644 index 00000000..c9226667 --- /dev/null +++ b/fpcsrc/rtl/aarch64/strings.inc @@ -0,0 +1,17 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 2003 by Florian Klaempfl, member of the + Free Pascal development team + + Processor dependent part of strings.pp, that can be shared with + sysutils unit. + + 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. + + **********************************************************************} + diff --git a/fpcsrc/rtl/aarch64/stringss.inc b/fpcsrc/rtl/aarch64/stringss.inc new file mode 100644 index 00000000..b3057282 --- /dev/null +++ b/fpcsrc/rtl/aarch64/stringss.inc @@ -0,0 +1,18 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Jonas Maebe, member of the + Free Pascal development team + + Processor dependent part of strings.pp, not shared with + sysutils unit. + + 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. + + **********************************************************************} + + diff --git a/fpcsrc/rtl/arm/arm.inc b/fpcsrc/rtl/arm/arm.inc index 09e9ed97..a62255d5 100644 --- a/fpcsrc/rtl/arm/arm.inc +++ b/fpcsrc/rtl/arm/arm.inc @@ -15,8 +15,6 @@ **********************************************************************} -{$asmmode gas} - {$ifndef FPC_SYSTEM_HAS_MOVE} {$define FPC_SYSTEM_FPC_MOVE} {$endif FPC_SYSTEM_HAS_MOVE} diff --git a/fpcsrc/rtl/arm/thumb2.inc b/fpcsrc/rtl/arm/thumb2.inc index 921ae243..248744d8 100644 --- a/fpcsrc/rtl/arm/thumb2.inc +++ b/fpcsrc/rtl/arm/thumb2.inc @@ -15,7 +15,7 @@ **********************************************************************} -{$asmmode gas} +{$asmmode divided} {$ifndef FPC_SYSTEM_HAS_MOVE} {$define FPC_SYSTEM_FPC_MOVE} diff --git a/fpcsrc/rtl/bsd/ostypes.inc b/fpcsrc/rtl/bsd/ostypes.inc index ab7395e7..00bcd5d5 100644 --- a/fpcsrc/rtl/bsd/ostypes.inc +++ b/fpcsrc/rtl/bsd/ostypes.inc @@ -30,8 +30,8 @@ {$endif} {$endif} -{$if (defined(darwin) and defined(cpuarm)) or defined(iphonesim)} - {$define darwinarm} +{$if (defined(darwin) and (defined(cpuarm) or defined(cpuaarch64))) or defined(iphonesim)} + {$define darwin_new_iostructs} {$endif} // CONST SYS_NMLN=65; @@ -88,7 +88,7 @@ TYPE st_qspare2 : cint64; {$else dragonfly} st_dev : dev_t; // inode's device -{$ifdef darwinarm} +{$ifdef darwin_new_iostructs} st_mode : mode_t; // inode protection mode st_nlink : nlink_t; // number of hard links st_ino : ino_t; // inode's number @@ -115,7 +115,7 @@ TYPE st_mtimensec : clong; // nsec of last data modification st_ctime : time_t; // time of last file status change st_ctimensec : clong; // nsec of last file status change -{$ifdef darwinarm} +{$ifdef darwin_new_iostructs} st_birthtime : time_t; // File creation time st_birthtimensec : clong; // nsec of file creation time {$endif} @@ -144,7 +144,7 @@ TYPE pStat = ^stat; { directory services } -{$ifndef darwinarm} +{$ifndef darwin_new_iostructs} dirent = record d_fileno : cuint32; // file number of entry d_reclen : cuint16; // length of this record @@ -152,7 +152,7 @@ TYPE d_namlen : cuint8; // length of string in d_name d_name : array[0..(255 + 1)-1] of char; // name must be no longer than this end; -{$else not darwinarm} +{$else not darwin_new_iostructs} {$packrecords 4} { available on Mac OS X 10.6 and later, and used by all iPhoneOS versions } dirent = record @@ -164,7 +164,7 @@ TYPE d_name : array[0..PATH_MAX-1] of char; // name must be no longer than this end; {$packrecords c} -{$endif darwinarm} +{$endif darwin_new_iostructs} TDirent = dirent; pDirent = ^dirent; diff --git a/fpcsrc/rtl/darwin/aarch64/sig_cpu.inc b/fpcsrc/rtl/darwin/aarch64/sig_cpu.inc new file mode 100644 index 00000000..13345b23 --- /dev/null +++ b/fpcsrc/rtl/darwin/aarch64/sig_cpu.inc @@ -0,0 +1,47 @@ + +{$IFDEF FPC} +{$PACKRECORDS C} +{$ENDIF} + + + + type + __darwin_arm_exception_state64 = record + __far : cuint64; + __esr : cuint32; + __exception : cuint32; + end; + + __darwin_arm_thread_state64 = record + __r : array[0..28] of cuint64; + __fp : cuint64; + __lr : cuint64; + __sp : cuint64; + __pc : cuint64; + __cpsr : cuint32; + end; + + __darwin_arm_neon_state64 = record + { actually an array of cuint128 } + __r : array[0..31] of record l1,l2: cuint64; end; + __fpsr : cuint32; + __fpcr : cuint32; + { array of cuint128 is aligned/padded to multiple of 16 bytes } + pad: cuint64; + end; + + __darwin_arm_debug_state64 = record + __bvr : array[0..15] of cuint64; + __bcr : array[0..15] of cuint64; + __wvr : array[0..15] of cuint64; + __wcr : array[0..15] of cuint64; + __mdscr_el1: cuint64; + end; + + mcontext_t = record + __es : __darwin_arm_exception_state64; + __ss : __darwin_arm_thread_state64; + __fs : __darwin_arm_neon_state64; + end; + + diff --git a/fpcsrc/rtl/darwin/aarch64/sighnd.inc b/fpcsrc/rtl/darwin/aarch64/sighnd.inc new file mode 100644 index 00000000..e9a7d420 --- /dev/null +++ b/fpcsrc/rtl/darwin/aarch64/sighnd.inc @@ -0,0 +1,61 @@ +{ + This file is part of the Free Pascal run time library. + (c) 2008 by Jonas Maebe + member of the Free Pascal development team. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + Signalhandler for Darwin/arm + + 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. +} + + +procedure SignalToRunerror(Sig: cint; info : PSigInfo; SigContext:PSigContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl; +var + res : word; +begin + res:=0; + case sig of + SIGFPE : + begin + Case Info^.si_code Of + FPE_FLTDIV, + FPE_INTDIV : Res:=200; { floating point divide by zero } + FPE_FLTOVF : Res:=205; { floating point overflow } + FPE_FLTUND : Res:=206; { floating point underflow } + FPE_FLTRES, { floating point inexact result } + FPE_FLTINV : Res:=207; { invalid floating point operation } + Else + Res:=207; {coprocessor error} + end; + { clear "exception happened" flags } + SigContext^.uc_mcontext^.__fs.__fpsr:=SigContext^.uc_mcontext^.__fs.__fpsr and not(fpu_exception_mask shr fpu_exception_mask_to_status_mask_shift); + end; + SIGBUS: + res:=214; + SIGILL, + SIGSEGV : + res:=216; + SIGINT: + res:=217; + SIGQUIT: + res:=233; + end; + {$ifdef FPC_USE_SIGPROCMASK} + reenable_signal(sig); + {$endif } + + { return to trampoline } + if res <> 0 then + begin + SigContext^.uc_mcontext^.__ss.__r[0] := res; + SigContext^.uc_mcontext^.__ss.__r[1] := SigContext^.uc_mcontext^.__ss.__pc; + SigContext^.uc_mcontext^.__ss.__r[2] := SigContext^.uc_mcontext^.__ss.__fp; + pointer(SigContext^.uc_mcontext^.__ss.__pc) := @HandleErrorAddrFrame; + end; +end; + diff --git a/fpcsrc/rtl/darwin/extres_multiarch.inc b/fpcsrc/rtl/darwin/extres_multiarch.inc index 0d80d355..a9a1eb73 100644 --- a/fpcsrc/rtl/darwin/extres_multiarch.inc +++ b/fpcsrc/rtl/darwin/extres_multiarch.inc @@ -30,27 +30,21 @@ const {$ENDIF} FPCRES_EXT = '.fpcres'; FPCRES_ARCH = - {$IFDEF CPUI386} + {$if defined(cpui386)} '.i386'; - {$ELSE} - {$IFDEF CPUX86_64} - '.x86_64'; - {$ELSE} - {$IFDEF CPUPOWERPC32} - '.powerpc'; - {$ELSE} - {$IFDEF CPUPOWERPC64} - '.powerpc64'; - {$ELSE} - {$IFDEF CPUARM} - '.arm'; - {$ELSE} - ''; - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} + {$elseif defined(cpux86_64)} + '.x86_64'; + {$elseif defined(cpupowerpc32)} + '.powerpc'; + {$elseif defined(cpupowerpc64)} + '.powerpc64'; + {$elseif defined(cpuarm)} + '.arm'; + {$elseif defined(cpuaarch64)} + '.aarch64'; + {$else} + {$error add support for cpu architecture} + {$endif} type TExtHeader = packed record diff --git a/fpcsrc/rtl/darwin/ptypes.inc b/fpcsrc/rtl/darwin/ptypes.inc index 15fbb9c9..aa12ebcb 100644 --- a/fpcsrc/rtl/darwin/ptypes.inc +++ b/fpcsrc/rtl/darwin/ptypes.inc @@ -35,7 +35,7 @@ type pGid = ^gid_t; TIOCtlRequest = cuLong; -{$if not defined(cpuarm) and not defined(iphonesim)} +{$if not defined(cpuarm) and not defined(aarch64) and not defined(iphonesim)} ino_t = cuint32; { used for file serial numbers } {$else} ino_t = cuint64; @@ -144,7 +144,7 @@ type val: array[0..1] of cint32; end; -{$if defined(cpuarm) or defined(iphonesim)} +{$if defined(cpuarm) or defined(cpuaarch64) or defined(iphonesim)} { structure used on iPhoneOS and available on Mac OS X 10.6 and later } tstatfs = record bsize : cuint32; diff --git a/fpcsrc/rtl/darwin/signal.inc b/fpcsrc/rtl/darwin/signal.inc index a3f843b9..78de160c 100644 --- a/fpcsrc/rtl/darwin/signal.inc +++ b/fpcsrc/rtl/darwin/signal.inc @@ -193,7 +193,11 @@ {$ifdef cpuarm} {$include arm/sig_cpu.inc} {$else cpuarm} +{$ifdef cpuaarch64} + {$include aarch64/sig_cpu.inc} +{$else cpuaarch64} {$error Unsupported cpu type!} +{$endif cpuaarch64} {$endif cpuarm} {$endif cpux86_64} {$endif cpui386} diff --git a/fpcsrc/rtl/inc/ctypes.pp b/fpcsrc/rtl/inc/ctypes.pp index 9376ff1b..90c02620 100644 --- a/fpcsrc/rtl/inc/ctypes.pp +++ b/fpcsrc/rtl/inc/ctypes.pp @@ -110,6 +110,10 @@ type {$define longdouble_is_double} {$ifend} +{$if defined(darwin) and defined(cpuaarch64)} + {$define longdouble_is_double} +{$ifend} + {$ifndef FPUNONE} {$if defined(longdouble_is_double) or not defined(FPC_HAS_CEXTENDED)} clongdouble=double; diff --git a/fpcsrc/rtl/inc/objc.pp b/fpcsrc/rtl/inc/objc.pp index 088d7e55..e7fc167c 100644 --- a/fpcsrc/rtl/inc/objc.pp +++ b/fpcsrc/rtl/inc/objc.pp @@ -3,7 +3,7 @@ unit objc; {$ifdef darwin} {$define targethandled} -{$if defined(iphonesim) or defined(cpuarm) or defined(cpux86_64) or defined(cpupowerpc64)} +{$if defined(iphonesim) or defined(cpuarm) or defined(cpux86_64) or defined(cpupowerpc64) or defined(cpuaarch64)} {$i objcnf.inc} {$endif} diff --git a/fpcsrc/rtl/inc/objcnf.inc b/fpcsrc/rtl/inc/objcnf.inc index f4697924..ba93ab76 100644 --- a/fpcsrc/rtl/inc/objcnf.inc +++ b/fpcsrc/rtl/inc/objcnf.inc @@ -172,12 +172,16 @@ type function objc_msgSend(self: id; op: SEL): id; cdecl; varargs; external libname; function objc_msgSendSuper(const super: pobjc_super; op: SEL): id; cdecl; varargs; external libname; function objc_msgSendSuper2(const super: pobjc_super; op: SEL): id; cdecl; varargs; weakexternal libname; { Mac OS X 10.6 and later } - { The following two are declared as procedures with the hidden result pointer - as their first parameter. This corresponds to the declaration below as far - as the code generator is concerned (and is easier to handle in the compiler). } +{ the AArch64 ABI does not require special handling of struct returns, so no + special handlers are provided/required } +{$ifndef cpuaarch64} +{ The following two are declared as procedures with the hidden result pointer + as their first parameter. This corresponds to the declaration below as far + as the code generator is concerned (and is easier to handle in the compiler). } function objc_msgSend_stret(self: id; op: SEL): tdummyrecbyaddrresult; cdecl; varargs; external libname; function objc_msgSendSuper_stret(const super: pobjc_super; op: SEL): tdummyrecbyaddrresult; cdecl; varargs; external libname; function objc_msgSendSuper2_stret(const super: pobjc_super; op: SEL): tdummyrecbyaddrresult; cdecl; varargs; weakexternal libname; +{$endif cpuaarch64} { This one actually also exists to return extended on x86_64, but we don't support that yet } @@ -230,7 +234,9 @@ type function class_getInstanceMethod(cls:pobjc_class; name:SEL):Method; cdecl; external libname; function class_getClassMethod(cls:pobjc_class; name:SEL):Method; cdecl; external libname; function class_getMethodImplementation(cls:pobjc_class; name:SEL):IMP; cdecl; external libname; +{$ifndef cpuaarch64} function class_getMethodImplementation_stret(cls:pobjc_class; name:SEL):IMP; cdecl; external libname; +{$endif cpuaarch64} function class_respondsToSelector(cls:pobjc_class; sel:SEL):BOOL; cdecl; external libname; function class_copyMethodList(cls:pobjc_class; outCount:pdword):PMethod; cdecl; external libname; diff --git a/fpcsrc/rtl/inc/system.inc b/fpcsrc/rtl/inc/system.inc index 3787f13b..5f4a4544 100644 --- a/fpcsrc/rtl/inc/system.inc +++ b/fpcsrc/rtl/inc/system.inc @@ -264,6 +264,13 @@ function do_isdevice(handle:thandle):boolean;forward; {$endif cpumips} {$endif not cpumipsel} +{$ifdef cpuaarch64} + {$ifdef SYSPROCDEFINED} + {$Error Can't determine processor type !} + {$endif} + {$i aarch64.inc} { Case dependent, don't change } + {$define SYSPROCDEFINED} +{$endif cpuaarch64} {$ifndef SYSPROCDEFINED} {$Error Can't determine processor type !} diff --git a/fpcsrc/rtl/inc/systemh.inc b/fpcsrc/rtl/inc/systemh.inc index 5f7ed3fb..10ff8b20 100644 --- a/fpcsrc/rtl/inc/systemh.inc +++ b/fpcsrc/rtl/inc/systemh.inc @@ -332,6 +332,22 @@ Type FarPointer = Pointer; {$endif CPUAVR} +{$ifdef CPUAARCH64} + {$define DEFAULT_DOUBLE} + + {$define SUPPORT_SINGLE} + {$define SUPPORT_DOUBLE} + + ValReal = Double; + + { map comp to int64, but this doesn't mean we compile the comp support in! } + Comp = Int64; + PComp = ^Comp; + + FarPointer = Pointer; +{$endif CPUAARCH64} + + {$ifdef CPU64} SizeInt = Int64; SizeUInt = QWord; @@ -861,13 +877,13 @@ function NtoLE(const AValue: QWord): QWord;{$ifdef SYSTEMINLINE}inline;{$endif} {$define FPC_HAS_INTERNAL_ROX_WORD} {$endif defined(cpux86_64) or defined(cpui386)} -{$if defined(cpux86_64) or defined(cpui386) or defined(arm) or defined(powerpc) or defined(powerpc64)} +{$if defined(cpux86_64) or defined(cpui386) or defined(arm) or defined(powerpc) or defined(powerpc64) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_ROX_DWORD} -{$endif defined(cpux86_64) or defined(cpui386) or defined(arm) or defined(powerpc) or defined(powerpc64)} +{$endif defined(cpux86_64) or defined(cpui386) or defined(arm) or defined(powerpc) or defined(powerpc64) or defined(cpuaarch64)} -{$if defined(cpux86_64) or defined(powerpc64)} +{$if defined(cpux86_64) or defined(powerpc64) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_ROX_QWORD} -{$endif defined(cpux86_64) or defined(powerpc64)} +{$endif defined(cpux86_64) or defined(powerpc64) or defined(cpuaarch64)} {$endif FPC_HAS_INTERNAL_ROX} @@ -942,9 +958,9 @@ function RolQWord(Const AValue : QWord;const Dist : Byte): QWord;{$ifdef SYSTEMI {$define FPC_HAS_INTERNAL_SAR_DWORD} { $endif defined(cpux86_64) or defined(cpui386) or defined(arm) or defined(powerpc) or defined(powerpc64) or defined(mips) or defined(mipsel)} -{$if defined(cpux86_64) or defined(powerpc64)} +{$if defined(cpux86_64) or defined(powerpc64) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_SAR_QWORD} -{$endif defined(cpux86_64) or defined(powerpc64)} +{$endif defined(cpux86_64) or defined(powerpc64) or defined(cpuaarch64)} {$endif FPC_HAS_INTERNAL_SAR} @@ -976,23 +992,23 @@ function fpc_SarInt64(Const AValue : Int64;const Shift : Byte): Int64;compilerpr {$endif FPC_HAS_INTERNAL_SAR_QWORD} {$ifdef FPC_HAS_INTERNAL_BSF} -{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm)} +{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_BSF_BYTE} {$define FPC_HAS_INTERNAL_BSF_WORD} {$define FPC_HAS_INTERNAL_BSF_DWORD} {$endif} -{$if defined(cpux86_64)} +{$if defined(cpux86_64) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_BSF_QWORD} {$endif} {$endif} {$ifdef FPC_HAS_INTERNAL_BSR} -{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm)} +{$if defined(cpui386) or defined(cpux86_64) or defined(cpuarm) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_BSR_BYTE} {$define FPC_HAS_INTERNAL_BSR_WORD} {$define FPC_HAS_INTERNAL_BSR_DWORD} {$endif} -{$if defined(cpux86_64)} +{$if defined(cpux86_64) or defined(cpuaarch64)} {$define FPC_HAS_INTERNAL_BSR_QWORD} {$endif} {$endif} diff --git a/fpcsrc/rtl/linux/aarch64/bsyscall.inc b/fpcsrc/rtl/linux/aarch64/bsyscall.inc new file mode 100644 index 00000000..c690ebeb --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/bsyscall.inc @@ -0,0 +1 @@ +{ nothing } diff --git a/fpcsrc/rtl/linux/aarch64/cprt0.as b/fpcsrc/rtl/linux/aarch64/cprt0.as new file mode 100644 index 00000000..fd83610f --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/cprt0.as @@ -0,0 +1,81 @@ +/* + Start-up code for Free Pascal Compiler when linking with C library. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +*/ + + .text + .align 2 + + .globl _start + .type _start,#function +_start: + /* Initialise FP to zero */ + mov x29,#0 + + /* This is rtld_fini */ + mov x5,x0 + + /* Get argc, argv, envp */ + ldr x1,[sp] + add x2,sp,#8 + add x11,x1,#1 + add x11,x2,x11,lsl #3 + + /* Save argc, argv, envp, and initial stack pointer */ + adrp x10,:got:operatingsystem_parameter_argc + ldr x10,[x10,#:got_lo12:operatingsystem_parameter_argc] + str x1,[x10] + adrp x10,:got:operatingsystem_parameter_argv + ldr x10,[x10,#:got_lo12:operatingsystem_parameter_argv] + str x2,[x10] + adrp x10,:got:operatingsystem_parameter_envp + ldr x10,[x10,#:got_lo12:operatingsystem_parameter_envp] + str x11,[x10] + adrp x10,:got:__stkptr + ldr x10,[x10,#:got_lo12:__stkptr] + mov x6,sp + str x6,[x10] + + /* __libc_start_main(main, argc, argv, + init, fini, rtld_fini, stack_end) */ + adrp x0,:got:PASCALMAIN + ldr x0,[x0,#:got_lo12:PASCALMAIN] + adrp x3,:got:__libc_csu_init + ldr x3,[x3,#:got_lo12:__libc_csu_init] + adrp x4,:got:__libc_csu_fini + ldr x4,[x4,#:got_lo12:__libc_csu_fini] + bl __libc_start_main + + /* This should never happen */ + b abort + + .globl _haltproc + .type _haltproc,#function +_haltproc: + adrp x0,:got:operatingsystem_result + ldr x0,[x0,#:got_lo12:operatingsystem_result] + ldr w0,[x0] + mov w8,#94 // syscall_nr_exit_group + svc #0 + b _haltproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .align 3 + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start + + .bss + .align 3 + + .comm __stkptr,8 + + .comm operatingsystem_parameter_envp,8 + .comm operatingsystem_parameter_argc,8 + .comm operatingsystem_parameter_argv,8 + + .section .note.GNU-stack,"",%progbits diff --git a/fpcsrc/rtl/linux/aarch64/dllprt0.as b/fpcsrc/rtl/linux/aarch64/dllprt0.as new file mode 100644 index 00000000..e91b7585 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/dllprt0.as @@ -0,0 +1,72 @@ +/* + Start-up code for Free Pascal Compiler in a shared library, + not linking with C library. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +*/ + + .text + .align 2 + + .globl _startlib + .type _startlib,#function +_startlib: + .globl FPC_SHARED_LIB_START + .type FPC_SHARED_LIB_START,#function +FPC_SHARED_LIB_START: + stp x29,x30,[sp,#-16]! + + /* Save argc, argv and envp */ + adrp x9,:got:operatingsystem_parameter_argc + ldr x9,[x9,#:got_lo12:operatingsystem_parameter_argc] + str x0,[x9] + adrp x9,:got:operatingsystem_parameter_argv + ldr x9,[x9,#:got_lo12:operatingsystem_parameter_argv] + str x1,[x9] + adrp x9,:got:operatingsystem_parameter_envp + ldr x9,[x9,#:got_lo12:operatingsystem_parameter_envp] + str x2,[x9] + + /* Save initial stackpointer */ + adrp x9,:got:__stkptr + ldr x9,[x9,#:got_lo12:__stkptr] + mov x10,sp + str x10,[x9] + + /* Call main */ + bl PASCALMAIN + + /* Return */ + ldp x29,x30,[sp],#16 + ret + + .globl _haltproc + .type _haltproc,#function +_haltproc: + adrp x0,:got:operatingsystem_result + ldr x0,[x0,#:got_lo12:operatingsystem_result] + ldr w0,[x0] + mov w8,#94 // syscall_nr_exit_group + svc #0 + b _haltproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .align 3 + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start + + .bss + .align 3 + + .comm __dl_fini,8 + .comm __stkptr,8 + + .comm operatingsystem_parameter_envp,8 + .comm operatingsystem_parameter_argc,8 + .comm operatingsystem_parameter_argv,8 + + .section .note.GNU-stack,"",%progbits diff --git a/fpcsrc/rtl/linux/aarch64/gprt0.as b/fpcsrc/rtl/linux/aarch64/gprt0.as new file mode 100644 index 00000000..e3a1b591 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/gprt0.as @@ -0,0 +1,10 @@ +/* + Start-up code for Free Pascal Compiler when linking with C library + with profiling support. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +*/ + + .text + .align 2 + b xx_aarch64_gprt0_unimplemented diff --git a/fpcsrc/rtl/linux/aarch64/prt0.as b/fpcsrc/rtl/linux/aarch64/prt0.as new file mode 100644 index 00000000..277d3094 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/prt0.as @@ -0,0 +1,77 @@ +/* + Start-up code for Free Pascal Compiler, not in a shared library, + not linking with C library. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +*/ + + .text + .align 2 + + .globl _dynamic_start + .type _dynamic_start,#function +_dynamic_start: + ldr x10,=__dl_fini + str x0,[x10] + b _start + + .globl _start + .type _start,#function +_start: + /* Initialise FP to zero */ + mov x29,#0 + + /* Get argc, argv, envp */ + ldr x1,[sp] + add x2,sp,#8 + add x11,x1,#1 + add x11,x2,x11,lsl #3 + + /* Save argc, argv, envp, and initial stack pointer */ + ldr x10,=operatingsystem_parameter_argc + str x1,[x10] + ldr x10,=operatingsystem_parameter_argv + str x2,[x10] + ldr x10,=operatingsystem_parameter_envp + str x11,[x10] + ldr x10,=__stkptr + mov x6,sp + str x6,[x10] + + /* Call main */ + bl PASCALMAIN + + .globl _haltproc + .type _haltproc,#function +_haltproc: + ldr x10,=__dl_fini + ldr x0,[x10] + cbz x0,.Lexit + blr x0 +.Lexit: + ldr x10,=operatingsystem_result + ldr w0,[x10] + mov w8,#94 // syscall_nr_exit_group + svc #0 + b _haltproc + + /* Define a symbol for the first piece of initialized data. */ + .data + .align 3 + .globl __data_start +__data_start: + .long 0 + .weak data_start + data_start = __data_start + + .bss + .align 3 + + .comm __dl_fini,8 + .comm __stkptr,8 + + .comm operatingsystem_parameter_envp,8 + .comm operatingsystem_parameter_argc,8 + .comm operatingsystem_parameter_argv,8 + + .section .note.GNU-stack,"",%progbits diff --git a/fpcsrc/rtl/linux/aarch64/sighnd.inc b/fpcsrc/rtl/linux/aarch64/sighnd.inc new file mode 100644 index 00000000..011b63a9 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/sighnd.inc @@ -0,0 +1,44 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Michael Van Canneyt, + member of the Free Pascal development team. + + Signal handler is arch dependant due to processor to language + exception conversion. + + 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. + + **********************************************************************} + +procedure SignalToRunerror(Sig: longint; SigInfo: PSigInfo; UContext: PUContext); public name '_FPC_DEFAULTSIGHANDLER'; cdecl; + +var + res : word; +begin + res:=0; + case sig of + SIGFPE: + res:=207; + SIGILL: + res:=216; + SIGSEGV : + res:=216; + SIGBUS: + res:=214; + SIGINT: + res:=217; + SIGQUIT: + res:=233; + end; + reenable_signal(sig); + { give runtime error at the position where the signal was raised } + if res<>0 then + HandleErrorAddrFrame(res, + pointer(uContext^.uc_mcontext.pc), + pointer(uContext^.uc_mcontext.regs[29])); +end; diff --git a/fpcsrc/rtl/linux/aarch64/sighndh.inc b/fpcsrc/rtl/linux/aarch64/sighndh.inc new file mode 100644 index 00000000..8fa6a35e --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/sighndh.inc @@ -0,0 +1,47 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Jonas Maebe, + member of the Free Pascal development team. + + TSigContext and associated structures. + + 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. + + **********************************************************************} + +{$packrecords C} + +type + PSigContext = ^TSigContext; + TSigContext = record + fault_address : cULong; + regs : array[0..30] of cULong; + sp : cULong; + pc : cULong; + pstate : cULong; + __pad : cULong; + { The following field should be 16-byte-aligned. Currently the + directive for specifying alignment is buggy, so the preceding + field was added so that the record has the right size. } + __reserved : array[0..4095] of cUChar; + end; + + stack_t = record + ss_sp : pointer; + ss_flags : cInt; + ss_size : size_t; + end; + + PUContext = ^TUContext; + TUContext = record + uc_flags : cULong; + uc_link : PUContext; + uc_stack : stack_t; + uc_mcontext : TSigContext; + uc_sigmask : sigset_t; + end; diff --git a/fpcsrc/rtl/linux/aarch64/stat.inc b/fpcsrc/rtl/linux/aarch64/stat.inc new file mode 100644 index 00000000..6d694413 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/stat.inc @@ -0,0 +1,72 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Jonas Maebe, (c) 2005 Thomas Schatzl, + members of the Free Pascal development team. + + Contains the definition of the stat type for the PowerPC64 platform. + + 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. + + **********************************************************************} + +{ This structure was adapted from + + include/uapi/asm-generic/stat.h + + in Linux 4.0. Note that the stat record is the same for direct + syscalls as for when linking to libc. +} + +{$PACKRECORDS C} + stat = record + case integer of + 0 : ( + st_dev : cULong; + st_ino : cULong; + st_mode : cUInt; + st_nlink : cUInt; + st_uid : cUInt; + st_gid : cUInt; + st_rdev : cULong; + __pad1a : cULong; + st_size : cLong; + st_blksize : cInt; + __pad2a : cInt; + st_blocks : cLong; + st_atime : cLong; + st_atime_nsec : cULong; + st_mtime : cLong; + st_mtime_nsec : cULong; + st_ctime : cLong; + st_ctime_nsec : cULong; + __unused4a : cUInt; + __unused5a : cUInt; + ); + 1 : ( + dev : cULong deprecated; + ino : cULong deprecated; + mode : cUInt deprecated; + nlink : cUInt deprecated; + uid : cUInt deprecated; + gid : cUInt deprecated; + rdev : cULong deprecated; + __pad1b : cULong deprecated; + size : cLong deprecated; + blksize : cInt deprecated; + __pad2b : cInt deprecated; + blocks : cLong deprecated; + atime : cLong deprecated; + atime_nsec : cULong deprecated; + mtime : cLong deprecated; + mtime_nsec : cULong deprecated; + ctime : cLong deprecated; + ctime_nsec : cULong deprecated; + __unused4b : cUInt deprecated; + __unused5b : cUInt deprecated; + ); + end; diff --git a/fpcsrc/rtl/linux/aarch64/syscall.inc b/fpcsrc/rtl/linux/aarch64/syscall.inc new file mode 100644 index 00000000..5001aa60 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/syscall.inc @@ -0,0 +1,127 @@ +{ + This file is part of the Free Pascal run time library. + + Perform syscall with 0..6 arguments. + If syscall return value is negative, negate it, set errno, and return -1. + + Written by Edmund Grimley Evans in 2015 and released into the public domain. +} + +function FpSysCall(sysnr:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL0']; +asm + mov w8,w0 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL1']; +asm + mov w8,w0 + mov x0,x1 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL2']; +asm + mov w8,w0 + mov x0,x1 + mov x1,x2 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL3']; +asm + mov w8,w0 + mov x0,x1 + mov x1,x2 + mov x2,x3 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL4']; +asm + mov w8,w0 + mov x0,x1 + mov x1,x2 + mov x2,x3 + mov x3,x4 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL5']; +asm + mov w8,w0 + mov x0,x1 + mov x1,x2 + mov x2,x3 + mov x3,x4 + mov x4,x5 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; + +function FpSysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; +assembler; nostackframe; [public,alias:'FPC_SYSCALL6']; +asm + mov w8,w0 + mov x0,x1 + mov x1,x2 + mov x2,x3 + mov x3,x4 + mov x4,x5 + mov x5,x6 + svc #0 + tbz x0,#63,.Ldone + str x30,[sp,#-16]! + neg x0,x0 + bl seterrno + ldr x30,[sp],#16 + mov x0,#-1 +.Ldone: +end; diff --git a/fpcsrc/rtl/linux/aarch64/syscallh.inc b/fpcsrc/rtl/linux/aarch64/syscallh.inc new file mode 100644 index 00000000..6961a190 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/syscallh.inc @@ -0,0 +1,35 @@ +{ + Copyright (c) 2002 by Marco van de Voort + + Header for syscalls in system unit. + + 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., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + + **************************************************************************** + +} + +Type + TSysResult = Int64; + TSysParam = Int64; + +function Do_SysCall(sysnr:TSysParam):TSysResult; external name 'FPC_SYSCALL0'; +function Do_SysCall(sysnr,param1:TSysParam):TSysResult; external name 'FPC_SYSCALL1'; +function Do_SysCall(sysnr,param1,param2:TSysParam):TSysResult; external name 'FPC_SYSCALL2'; +function Do_SysCall(sysnr,param1,param2,param3:TSysParam):TSysResult; external name 'FPC_SYSCALL3'; +function Do_SysCall(sysnr,param1,param2,param3,param4:TSysParam):TSysResult; external name 'FPC_SYSCALL4'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5:TSysParam):TSysResult; external name 'FPC_SYSCALL5'; +function Do_SysCall(sysnr,param1,param2,param3,param4,param5,param6:TSysParam):TSysResult; external name 'FPC_SYSCALL6'; diff --git a/fpcsrc/rtl/linux/aarch64/sysnr.inc b/fpcsrc/rtl/linux/aarch64/sysnr.inc new file mode 100644 index 00000000..3763caa8 --- /dev/null +++ b/fpcsrc/rtl/linux/aarch64/sysnr.inc @@ -0,0 +1 @@ +{$i ../sysnr-gen.inc} diff --git a/fpcsrc/rtl/linux/bunxsysc.inc b/fpcsrc/rtl/linux/bunxsysc.inc index afd68b7b..c8d78496 100644 --- a/fpcsrc/rtl/linux/bunxsysc.inc +++ b/fpcsrc/rtl/linux/bunxsysc.inc @@ -297,7 +297,11 @@ end; function fpgetpgrp : pid_t; begin +{$if defined(generic_linux_syscalls)} + fpgetpgrp:=do_syscall(syscall_nr_getpgid,0); +{$else} fpgetpgrp:=do_syscall(syscall_nr_getpgrp); +{$endif} end; function fpsetsid : pid_t; @@ -327,29 +331,59 @@ Function fplink(existing:pchar;newone:pchar):cint; In effect, new will be the same file as old. } begin +{$if defined(generic_linux_syscalls)} + fpLink:=Do_Syscall(syscall_nr_linkat,AT_FDCWD,TSysParam(existing),AT_FDCWD,TSysParam(newone),0); +{$else} fpLink:=Do_Syscall(syscall_nr_link,TSysParam(existing),TSysParam(newone)); +{$endif} end; Function fpmkfifo(path:pchar;mode:mode_t):cint; begin +{$if defined(generic_linux_syscalls)} +fpmkfifo:=do_syscall(syscall_nr_mknodat,AT_FDCWD,TSysParam(path),TSysParam(mode or S_IFIFO),TSysParam(0)); +{$else} fpmkfifo:=do_syscall(syscall_nr_mknod,TSysParam(path),TSysParam(mode or S_IFIFO),TSysParam(0)); +{$endif} end; Function fpchmod(path:pchar;mode:mode_t):cint; begin +{$if defined(generic_linux_syscalls)} + fpchmod:=do_syscall(syscall_nr_fchmodat,AT_FDCWD,TSysParam(path),TSysParam(mode),0); +{$else} fpchmod:=do_syscall(syscall_nr_chmod,TSysParam(path),TSysParam(mode)); +{$endif} end; Function fpchown(path:pchar;owner:uid_t;group:gid_t):cint; begin +{$if defined(generic_linux_syscalls)} + fpChOwn:=do_syscall(syscall_nr_fchownat,AT_FDCWD,TSysParam(path),TSysParam(owner),TSysParam(group),0); +{$else} fpChOwn:=do_syscall(syscall_nr_chown,TSysParam(path),TSysParam(owner),TSysParam(group)); +{$endif} end; -{$ifndef NO_SYSCALL_UTIME} +{$if defined(generic_linux_syscalls)} + +Function fpUtime(path:pchar;times:putimbuf):cint; +var + tsa: Array[0..1] of timespec; +begin + tsa[0].tv_sec := times^.actime; + tsa[0].tv_nsec := 0; + tsa[1].tv_sec := times^.modtime; + tsa[1].tv_nsec := 0; + fputime:=do_syscall(syscall_nr_utimensat,AT_FDCWD,TSysParam(path), + TSysParam(@tsa),0); +end; + +{$elseif not defined(NO_SYSCALL_UTIME)} Function fpUtime(path:pchar;times:putimbuf):cint; @@ -377,7 +411,11 @@ end; Function fppipe(var fildes : tfildes):cint; begin +{$if defined(generic_linux_syscalls)} + fppipe:=do_syscall(syscall_nr_pipe2,TSysParam(@fildes),0); +{$else} fppipe:=do_syscall(syscall_nr_pipe,TSysParam(@fildes)); +{$endif} end; {$endif FPC_BASEUNIX_HAS_FPPIPE} @@ -422,6 +460,18 @@ Function fpSelect(N:cint;readfds,writefds,exceptfds:pfdSet;TimeOut:PTimeVal):cin Select checks whether the file descriptor sets in readfs/writefs/exceptfs have changed. } +{$if defined(generic_linux_syscalls)} + +var ts : timespec; +begin + ts.tv_sec := timeout^.tv_sec; + ts.tv_nsec := timeout^.tv_usec * 1000; + fpSelect:=do_syscall(syscall_nr_pselect6,n, + tsysparam(readfds),tsysparam(writefds), + tsysparam(exceptfds),tsysparam(@ts),0); +end; + +{$else} begin {$ifdef cpux86_64} @@ -436,10 +486,27 @@ begin {$endif bunxfunc_fpselect_implemented} end; +{$endif} + function fpPoll(fds: ppollfd; nfds: cuint; timeout: clong): cint; +{$if defined(generic_linux_syscalls)} +var ts : timespec; +begin + if timeout<0 then + fpPoll:=do_syscall(syscall_nr_ppoll,tsysparam(fds),tsysparam(nfds),0,0) + else + begin + ts.tv_sec := timeout div 1000; + ts.tv_nsec := (timeout mod 1000) * 1000000; + fpPoll:=do_syscall(syscall_nr_ppoll,tsysparam(fds),tsysparam(nfds), + tsysparam(@ts),0); + end +end; +{$else} begin fpPoll:=do_syscall(syscall_nr_poll,tsysparam(fds),tsysparam(nfds),tsysparam(timeout)); end; +{$endif} Function fpLstat(path:pchar;Info:pstat):cint; { @@ -447,6 +514,9 @@ Function fpLstat(path:pchar;Info:pstat):cint; } begin +{$if defined(generic_linux_syscalls)} + fpLStat:=do_syscall(syscall_nr_fstatat,AT_FDCWD,TSysParam(path),TSysParam(info),0) +{$else} fpLStat:=do_syscall( {$ifdef cpu64} syscall_nr_lstat, @@ -454,6 +524,7 @@ begin syscall_nr_lstat64, {$endif} TSysParam(path),TSysParam(info)); +{$endif} end; @@ -465,12 +536,12 @@ function fpNice(N:cint):cint; Doesn't exist in BSD. Linux emu uses setpriority in a construct as below: } -{$ifdef cpux86_64} +{$if defined(generic_linux_syscalls) or defined(cpux86_64)} var oldprio : cint; {$endif} begin -{$ifdef cpux86_64} +{$if defined(generic_linux_syscalls) or defined(cpux86_64)} oldprio:=fpGetPriority(Prio_Process,0); fpNice:=fpSetPriority(Prio_Process,0,oldprio+N); if fpNice=0 then @@ -536,7 +607,11 @@ Function fpSymlink(oldname,newname:pchar):cint; } begin +{$if defined(generic_linux_syscalls)} + fpsymlink:=do_syscall(syscall_nr_symlinkat,TSysParam(oldname),AT_FDCWD,TSysParam(newname)); +{$else} fpsymlink:=do_syscall(syscall_nr_symlink,TSysParam(oldname),TSysParam(newname)); +{$endif} end; function Fppread(fd: cint; buf: pchar; nbytes : size_t; offset:Toff): ssize_t; [public, alias : 'FPC_SYSC_PREAD']; diff --git a/fpcsrc/rtl/linux/linux.pp b/fpcsrc/rtl/linux/linux.pp index d9f4f51b..4f4333f9 100644 --- a/fpcsrc/rtl/linux/linux.pp +++ b/fpcsrc/rtl/linux/linux.pp @@ -17,6 +17,8 @@ **********************************************************************} unit Linux; +{$i osdefs.inc} + {$packrecords c} {$ifdef FPC_USE_LIBC} {$linklib rt} // for clock* functions @@ -527,7 +529,11 @@ end; function epoll_create(size: cint): cint; begin +{$if defined(generic_linux_syscalls)} + epoll_create := do_syscall(syscall_nr_epoll_create1,0) +{$else} epoll_create := do_syscall(syscall_nr_epoll_create,tsysparam(size)); +{$endif} end; function epoll_ctl(epfd, op, fd: cint; event: pepoll_event): cint; @@ -538,8 +544,13 @@ end; function epoll_wait(epfd: cint; events: pepoll_event; maxevents, timeout: cint): cint; begin +{$if defined(generic_linux_syscalls)} + epoll_wait := do_syscall(syscall_nr_epoll_pwait, tsysparam(epfd), + tsysparam(events), tsysparam(maxevents), tsysparam(timeout),0); +{$else} epoll_wait := do_syscall(syscall_nr_epoll_wait, tsysparam(epfd), tsysparam(events), tsysparam(maxevents), tsysparam(timeout)); +{$endif} end; function capget(header:Puser_cap_header;data:Puser_cap_data):cint; @@ -695,7 +706,11 @@ end; function inotify_init1(flags:cint):cint; begin +{$if defined(generic_linux_syscalls)} + inotify_init1:=do_SysCall(syscall_nr_inotify_init1,tsysparam(flags)); +{$else} inotify_init1:=do_SysCall(syscall_nr_inotify_init,tsysparam(flags)); +{$endif} end; function inotify_add_watch(fd:cint; name:Pchar; mask:cuint32):cint; diff --git a/fpcsrc/rtl/linux/oldlinux.pp b/fpcsrc/rtl/linux/oldlinux.pp index 1a878257..5fd08913 100644 --- a/fpcsrc/rtl/linux/oldlinux.pp +++ b/fpcsrc/rtl/linux/oldlinux.pp @@ -1924,9 +1924,16 @@ Function Sys_Mkdir(Filename:pchar;mode:longint):longint; var regs : SysCallregs; begin +{$if defined(generic_linux_syscalls)} + regs.reg2:=AT_FDCWD; + regs.reg3:=longint(filename); + regs.reg4:=mode; + Sys_MkDir:=SysCall(SysCall_nr_mkdirat,regs); +{$else} regs.reg2:=longint(filename); regs.reg3:=mode; Sys_MkDir:=SysCall(SysCall_nr_mkdir,regs); +{$endif} end; @@ -1935,8 +1942,15 @@ Function Sys_Rmdir(Filename:pchar):longint; var regs : SysCallregs; begin +{$if defined(generic_linux_syscalls)} + regs.reg2:=AT_FDCWD; + regs.reg3:=longint(filename); + regs.reg4:=AT_REMOVEDIR; + Sys_Rmdir:=SysCall(SysCall_nr_unlinkat,regs); +{$else} regs.reg2:=longint(filename); Sys_Rmdir:=SysCall(SysCall_nr_rmdir,regs); +{$endif} end; @@ -2744,7 +2758,18 @@ var begin sr.reg2:=oldfile; sr.reg3:=newfile; +{$if defined(generic_linux_syscalls)} + sr.reg4:=0; + if oldfile<>newfile then + SysCall(Syscall_nr_dup3,sr) + else + begin + sr.reg3:=F_GetFd; + SysCall(Syscall_nr_fcntl,sr); + end; +{$else} SysCall(Syscall_nr_dup2,sr); +{$endif} linuxerror:=errno; Dup2:=(LinuxError=0); end; @@ -2782,7 +2807,12 @@ var regs : SysCallregs; begin regs.reg2:=longint(@pip); +{$if defined(generic_linux_syscalls)} + regs.reg3:=0; + SysCall(SysCall_nr_pipe2,regs); +{$else} SysCall(SysCall_nr_pipe,regs); +{$endif} pipe_in:=pip[1]; pipe_out:=pip[2]; linuxerror:=errno; diff --git a/fpcsrc/rtl/linux/osdefs.inc b/fpcsrc/rtl/linux/osdefs.inc index cfb86fae..a8da1dd8 100644 --- a/fpcsrc/rtl/linux/osdefs.inc +++ b/fpcsrc/rtl/linux/osdefs.inc @@ -85,3 +85,7 @@ {$endif FPC_ABI_EABI} {$endif cpuarm} +{$ifdef cpuaarch64} + {$define generic_linux_syscalls} + {$undef usestime} +{$endif cpuaarch64} diff --git a/fpcsrc/rtl/linux/ossysc.inc b/fpcsrc/rtl/linux/ossysc.inc index ad360c4d..52f80bea 100644 --- a/fpcsrc/rtl/linux/ossysc.inc +++ b/fpcsrc/rtl/linux/ossysc.inc @@ -20,7 +20,7 @@ *****************************************************************************} function Fptime(tloc:pTime_t): Time_t; [public, alias : 'FPC_SYSC_TIME']; -{$ifdef FPC_USEGETTIMEOFDAY} +{$if defined(generic_linux_syscalls) or defined(FPC_USEGETTIMEOFDAY)} VAR tv : timeval; tz : timezone; retval : longint; @@ -49,7 +49,11 @@ end; function Fpopen(path: pchar; flags : cint; mode: mode_t):cint; [public, alias : 'FPC_SYSC_OPEN']; Begin +{$if defined(generic_linux_syscalls)} + Fpopen:=do_syscall(syscall_nr_openat,AT_FDCWD,TSysParam(path),TSysParam(flags or O_LARGEFILE),TSysParam(mode)); +{$else} Fpopen:=do_syscall(syscall_nr_open,TSysParam(path),TSysParam(flags or O_LARGEFILE),TSysParam(mode)); +{$endif} End; function Fpclose(fd : cint): cint; [public, alias : 'FPC_SYSC_CLOSE']; @@ -98,20 +102,32 @@ end; function Fpunlink(path: pchar): cint; [public, alias : 'FPC_SYSC_UNLINK']; begin +{$if defined(generic_linux_syscalls)} + Fpunlink:=do_syscall(syscall_nr_unlinkat,AT_FDCWD,TSysParam(path),0); +{$else} Fpunlink:=do_syscall(syscall_nr_unlink,TSysParam(path)); +{$endif} end; function Fprename(old : pchar; newpath: pchar): cint; [public, alias : 'FPC_SYSC_RENAME']; begin +{$if defined(generic_linux_syscalls)} + Fprename:=do_syscall(syscall_nr_renameat,AT_FDCWD,TSysParam(old),AT_FDCWD,TSysParam(newpath)); +{$else} Fprename:=do_syscall(syscall_nr_rename,TSysParam(old),TSysParam(newpath)); +{$endif} end; function Fpstat(path: pchar; var buf: stat):cint; [public, alias : 'FPC_SYSC_STAT']; begin {$if defined(cpu64)} - Fpstat:=do_syscall(syscall_nr_stat,TSysParam(path),TSysParam(@buf)); + {$if defined(generic_linux_syscalls)} + Fpstat:=do_syscall(syscall_nr_fstatat,AT_FDCWD,TSysParam(path),TSysParam(@buf),0); + {$else} + Fpstat:=do_syscall(syscall_nr_stat,TSysParam(path),TSysParam(@buf)); + {$endif} {$else} Fpstat:=do_syscall(syscall_nr_stat64,TSysParam(path),TSysParam(@buf)); {$endif} @@ -130,13 +146,21 @@ end; function Fpmkdir(path : pchar; mode: mode_t):cint; [public, alias : 'FPC_SYSC_MKDIR']; begin +{$if defined(generic_linux_syscalls)} + Fpmkdir:=do_syscall(syscall_nr_mkdirat,AT_FDCWD,TSysParam(path),TSysParam(mode)); +{$else} Fpmkdir:=do_syscall(syscall_nr_mkdir,TSysParam(path),TSysParam(mode)); +{$endif} end; function Fprmdir(path : pchar): cint; [public, alias : 'FPC_SYSC_RMDIR']; begin +{$if defined(generic_linux_syscalls)} + Fprmdir:=do_syscall(syscall_nr_unlinkat,AT_FDCWD,TSysParam(path),AT_REMOVEDIR); +{$else} Fprmdir:=do_syscall(syscall_nr_rmdir,TSysParam(path)); +{$endif} end; function Fpopendir(dirname : pchar): pdir; [public, alias : 'FPC_SYSC_OPENDIR']; @@ -363,7 +387,11 @@ function Fpfstat(fd : cint; var sb : stat): cint; [public, alias : 'FPC_SYSC_FS begin {$if defined(cpu64)} - FpFStat:=do_SysCall(syscall_nr_fstat,TSysParam(fd),TSysParam(@sb)); + {$if defined(generic_linux_syscalls)} + FpFStat:=do_SysCall(syscall_nr_fstat,TSysParam(fd),TSysParam(@sb)); + {$else} + FpFStat:=do_SysCall(syscall_nr_fstat,TSysParam(fd),TSysParam(@sb)); + {$endif} {$else} FpFStat:=do_SysCall(syscall_nr_fstat64,TSysParam(fd),TSysParam(@sb)); {$endif} @@ -380,9 +408,14 @@ function Fpfork : pid_t; [public, alias : 'FPC_SYSC_FORK']; A negative value indicates that an error has occurred, the error is returned in LinuxError. } - +var + pid : Int64; Begin +{$if defined(generic_linux_syscalls)} + Fpfork:=Do_syscall(syscall_nr_clone,clone_flags_fork,0,0,0,TSysParam(@pid)); +{$else} Fpfork:=Do_syscall(SysCall_nr_fork); +{$endif} End; {$endif FPC_SYSTEM_HAS_FPFORK} @@ -425,7 +458,7 @@ function Fpwaitpid(pid : pid_t; stat_loc : pcint; options: cint): pid_t; [public } begin -{$ifdef WAIT4} +{$if defined(generic_linux_syscalls) or defined(WAIT4)} FpWaitPID:=do_syscall(syscall_nr_Wait4,PID,TSysParam(Stat_loc),options,0); {$else WAIT4} FpWaitPID:=do_syscall(syscall_nr_WaitPID,PID,TSysParam(Stat_loc),options); @@ -447,7 +480,11 @@ function Fpaccess(pathname : pchar; amode : cint): cint; [public, alias : 'FPC_S } begin +{$if defined(generic_linux_syscalls)} + FpAccess:=do_syscall(syscall_nr_faccessat,AT_FDCWD,TSysParam(pathname),amode,0); +{$else} FpAccess:=do_syscall(syscall_nr_access,TSysParam(pathname),amode); +{$endif} end; (* overloaded @@ -481,7 +518,16 @@ end; Function FpDup2(fildes,fildes2:cint):cint; [public, alias : 'FPC_SYSC_DUP2']; begin +{$if defined(generic_linux_syscalls)} + if fildes<>fildes2 then + Fpdup2:=do_syscall(syscall_nr_dup3,TSysParam(fildes),TSysParam(fildes2),0) + else if do_syscall(syscall_nr_fcntl,TSysParam(fildes),1)<>-1 then + Fpdup2:=fildes2 + else + Fpdup2:=-1; +{$else} Fpdup2:=do_syscall(syscall_nr_dup2,TSysParam(fildes),TSysParam(fildes2)); +{$endif} end; @@ -572,7 +618,11 @@ end; Function FpReadLink(name,linkname:pchar;maxlen:size_t):cint; [public, alias : 'FPC_SYSC_READLINK']; begin +{$if defined(generic_linux_syscalls)} + Fpreadlink:=do_syscall(syscall_nr_readlinkat,AT_FDCWD,TSysParam(name),TSysParam(linkname),maxlen); +{$else} Fpreadlink:=do_syscall(syscall_nr_readlink, TSysParam(name),TSysParam(linkname),maxlen); +{$endif} end; diff --git a/fpcsrc/rtl/linux/ostypes.inc b/fpcsrc/rtl/linux/ostypes.inc index ac19d74a..61242b75 100644 --- a/fpcsrc/rtl/linux/ostypes.inc +++ b/fpcsrc/rtl/linux/ostypes.inc @@ -290,7 +290,12 @@ CONST {$endif not cpumips} {$endif not cpusparc} -{$if defined(cpuarm) or defined(cpualpha) or defined(cpublackfin) or defined(cpum68k)} + AT_FDCWD = -100; + AT_REMOVEDIR = $200; + clone_flags_fork = $01200011; + { SIGCHLD | CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID } + +{$if defined(cpuarm) or defined(cpualpha) or defined(cpublackfin) or defined(cpum68k) or defined(aarch64)} O_LARGEFILE = $20000; {$endif} {$if defined(cpusparc) or defined(cpusparc64)} diff --git a/fpcsrc/rtl/linux/pmutext.inc b/fpcsrc/rtl/linux/pmutext.inc new file mode 100644 index 00000000..d7626038 --- /dev/null +++ b/fpcsrc/rtl/linux/pmutext.inc @@ -0,0 +1,58 @@ +{ + This file is part of the Free Pascal run time library. + Copyright (c) 1999-2000 by Peter Vreman + member of the Free Pascal development team. + + 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. + + **********************************************************************} + +{ definition of pthread_mutex_t, because needed in both ptypes.inc and } +{ in sysosh.inc } + +{ use a macro rather than a constant, so this name doesn't get exported + from the system unit interface; macro's have to be on at this point + because they're use to propagate the MUTEXTYPENAME here } + +{$if defined(CPUMIPS) or defined(cpuaarch64)} +{$define USE_PTHREAD_SIZEOF} + +{$if defined(cpuaarch64)} + {$define __SIZEOF_PTHREAD_MUTEX_T := 48} +{$elseif defined(CPU64)} + {$define __SIZEOF_PTHREAD_MUTEX_T := 40} +{$else CPU64} + {$define __SIZEOF_PTHREAD_MUTEX_T := 24} +{$endif CPU64} + +{$endif MIPS} + + MUTEXTYPENAME = record + case byte of +{$ifdef USE_PTHREAD_SIZEOF} + 0 : ( + __size : array[0..__SIZEOF_PTHREAD_MUTEX_T-1] of char; + __align : sizeint; + ); +{$endif} + 1 : ( + __m_reserved: longint; + __m_count: longint; + __m_owner: pointer; + __m_kind: longint; + __m_lock: record + __status: sizeint; + __spinlock: longint; + end; + ); + end; + +{$ifdef __SIZEOF_PTHREAD_MUTEX_T} +{$undef __SIZEOF_PTHREAD_MUTEX_T} +{$endif __SIZEOF_PTHREAD_MUTEX_T} +{$macro off} \ No newline at end of file diff --git a/fpcsrc/rtl/linux/ptypes.inc b/fpcsrc/rtl/linux/ptypes.inc index 14e6c181..f3b30270 100644 --- a/fpcsrc/rtl/linux/ptypes.inc +++ b/fpcsrc/rtl/linux/ptypes.inc @@ -30,12 +30,21 @@ and all three 32-bit systems returned completely identical types too introduction) } -{$ifdef CPUMIPS} +{$if defined(CPUMIPS) or defined(cpuaarch64)} {$define USE_PTHREAD_SIZEOF} -{$ifdef CPU64} +{$if defined(cpuaarch64)} +const + __SIZEOF_PTHREAD_ATTR_T = 64; + __SIZEOF_PTHREAD_MUTEXATTR_T = 8; + __SIZEOF_PTHREAD_COND_T = 48; + __SIZEOF_PTHREAD_CONDATTR_T = 8; + __SIZEOF_PTHREAD_RWLOCK_T = 56; + __SIZEOF_PTHREAD_RWLOCKATTR_T = 8; + __SIZEOF_PTHREAD_BARRIER_T = 32; + __SIZEOF_PTHREAD_BARRIERATTR_T = 8; +{$elseif defined(CPU64)} const __SIZEOF_PTHREAD_ATTR_T = 56; - __SIZEOF_PTHREAD_MUTEX_T = 40; __SIZEOF_PTHREAD_MUTEXATTR_T = 4; __SIZEOF_PTHREAD_COND_T = 48; __SIZEOF_PTHREAD_CONDATTR_T = 4; @@ -46,7 +55,6 @@ const {$else : not CPU64, i.e. CPU32} const __SIZEOF_PTHREAD_ATTR_T = 36; - __SIZEOF_PTHREAD_MUTEX_T = 24; __SIZEOF_PTHREAD_MUTEXATTR_T = 4; __SIZEOF_PTHREAD_COND_T = 48; __SIZEOF_PTHREAD_CONDATTR_T = 4; @@ -55,7 +63,7 @@ const __SIZEOF_PTHREAD_BARRIER_T = 20; __SIZEOF_PTHREAD_BARRIERATTR_T = 4; {$endif CPU32} -{$endif MIPS} +{$endif} {$I ctypes.inc} {$packrecords c} @@ -256,24 +264,11 @@ Type __spinlock: cint; end; - pthread_mutex_t = record - {$ifdef USE_PTHREAD_SIZEOF} - case byte of - 0 : ( - __size : array[0..__SIZEOF_PTHREAD_MUTEX_T-1] of char; - __align : clong; - ); - 1 : ( - {$endif} - __m_reserved: cint; - __m_count: cint; - __m_owner: pointer; - __m_kind: cint; - __m_lock: _pthread_fastlock; - {$ifdef USE_PTHREAD_SIZEOF} - ); - {$endif} - end; +{$macro on} +{$define MUTEXTYPENAME := pthread_mutex_t} +{$i pmutext.inc} +{$undef MUTEXTYPENAME} +{$macro off} pthread_mutexattr_t = record {$ifdef USE_PTHREAD_SIZEOF} diff --git a/fpcsrc/rtl/linux/sysnr-gen.inc b/fpcsrc/rtl/linux/sysnr-gen.inc new file mode 100644 index 00000000..35258613 --- /dev/null +++ b/fpcsrc/rtl/linux/sysnr-gen.inc @@ -0,0 +1,277 @@ + +{ + System call numbers taken from include/uapi/asm-generic/unistd.h + in a 4.0 Linux kernel. They are therefore architecture-independent, + though only the newest architectures use this generic list. +} + +Const + syscall_nr_io_setup = 0; + syscall_nr_io_destroy = 1; + syscall_nr_io_submit = 2; + syscall_nr_io_cancel = 3; + syscall_nr_io_getevents = 4; + syscall_nr_setxattr = 5; + syscall_nr_lsetxattr = 6; + syscall_nr_fsetxattr = 7; + syscall_nr_getxattr = 8; + syscall_nr_lgetxattr = 9; + syscall_nr_fgetxattr = 10; + syscall_nr_listxattr = 11; + syscall_nr_llistxattr = 12; + syscall_nr_flistxattr = 13; + syscall_nr_removexattr = 14; + syscall_nr_lremovexattr = 15; + syscall_nr_fremovexattr = 16; + syscall_nr_getcwd = 17; + syscall_nr_lookup_dcookie = 18; + syscall_nr_eventfd2 = 19; + syscall_nr_epoll_create1 = 20; + syscall_nr_epoll_ctl = 21; + syscall_nr_epoll_pwait = 22; + syscall_nr_dup = 23; + syscall_nr_dup3 = 24; + syscall_nr_fcntl = 25; + syscall_nr_inotify_init1 = 26; + syscall_nr_inotify_add_watch = 27; + syscall_nr_inotify_rm_watch = 28; + syscall_nr_ioctl = 29; + syscall_nr_ioprio_set = 30; + syscall_nr_ioprio_get = 31; + syscall_nr_flock = 32; + syscall_nr_mknodat = 33; + syscall_nr_mkdirat = 34; + syscall_nr_unlinkat = 35; + syscall_nr_symlinkat = 36; + syscall_nr_linkat = 37; + syscall_nr_renameat = 38; + syscall_nr_umount2 = 39; + syscall_nr_mount = 40; + syscall_nr_pivot_root = 41; + syscall_nr_nfsservctl = 42; + syscall_nr_statfs = 43; + syscall_nr_fstatfs = 44; + syscall_nr_truncate = 45; + syscall_nr_ftruncate = 46; + syscall_nr_fallocate = 47; + syscall_nr_faccessat = 48; + syscall_nr_chdir = 49; + syscall_nr_fchdir = 50; + syscall_nr_chroot = 51; + syscall_nr_fchmod = 52; + syscall_nr_fchmodat = 53; + syscall_nr_fchownat = 54; + syscall_nr_fchown = 55; + syscall_nr_openat = 56; + syscall_nr_close = 57; + syscall_nr_vhangup = 58; + syscall_nr_pipe2 = 59; + syscall_nr_quotactl = 60; + syscall_nr_getdents64 = 61; + syscall_nr_lseek = 62; + syscall_nr_read = 63; + syscall_nr_write = 64; + syscall_nr_readv = 65; + syscall_nr_writev = 66; + syscall_nr_pread64 = 67; + syscall_nr_pwrite64 = 68; + syscall_nr_preadv = 69; + syscall_nr_pwritev = 70; + syscall_nr_sendfile = 71; + syscall_nr_pselect6 = 72; + syscall_nr_ppoll = 73; + syscall_nr_signalfd4 = 74; + syscall_nr_vmsplice = 75; + syscall_nr_splice = 76; + syscall_nr_tee = 77; + syscall_nr_readlinkat = 78; + syscall_nr_fstatat = 79; + syscall_nr_fstat = 80; + syscall_nr_sync = 81; + syscall_nr_fsync = 82; + syscall_nr_fdatasync = 83; + syscall_nr_sync_file_range = 84; + syscall_nr_timerfd_create = 85; + syscall_nr_timerfd_settime = 86; + syscall_nr_timerfd_gettime = 87; + syscall_nr_utimensat = 88; + syscall_nr_acct = 89; + syscall_nr_capget = 90; + syscall_nr_capset = 91; + syscall_nr_personality = 92; + syscall_nr_exit = 93; + syscall_nr_exit_group = 94; + syscall_nr_waitid = 95; + syscall_nr_set_tid_address = 96; + syscall_nr_unshare = 97; + syscall_nr_futex = 98; + syscall_nr_set_robust_list = 99; + syscall_nr_get_robust_list = 100; + syscall_nr_nanosleep = 101; + syscall_nr_getitimer = 102; + syscall_nr_setitimer = 103; + syscall_nr_kexec_load = 104; + syscall_nr_init_module = 105; + syscall_nr_delete_module = 106; + syscall_nr_timer_create = 107; + syscall_nr_timer_gettime = 108; + syscall_nr_timer_getoverrun = 109; + syscall_nr_timer_settime = 110; + syscall_nr_timer_delete = 111; + syscall_nr_clock_settime = 112; + syscall_nr_clock_gettime = 113; + syscall_nr_clock_getres = 114; + syscall_nr_clock_nanosleep = 115; + syscall_nr_syslog = 116; + syscall_nr_ptrace = 117; + syscall_nr_sched_setparam = 118; + syscall_nr_sched_setscheduler = 119; + syscall_nr_sched_getscheduler = 120; + syscall_nr_sched_getparam = 121; + syscall_nr_sched_setaffinity = 122; + syscall_nr_sched_getaffinity = 123; + syscall_nr_sched_yield = 124; + syscall_nr_sched_get_priority_max = 125; + syscall_nr_sched_get_priority_min = 126; + syscall_nr_sched_rr_get_interval = 127; + syscall_nr_restart_syscall = 128; + syscall_nr_kill = 129; + syscall_nr_tkill = 130; + syscall_nr_tgkill = 131; + syscall_nr_sigaltstack = 132; + syscall_nr_rt_sigsuspend = 133; + syscall_nr_rt_sigaction = 134; + syscall_nr_rt_sigprocmask = 135; + syscall_nr_rt_sigpending = 136; + syscall_nr_rt_sigtimedwait = 137; + syscall_nr_rt_sigqueueinfo = 138; + syscall_nr_rt_sigreturn = 139; + syscall_nr_setpriority = 140; + syscall_nr_getpriority = 141; + syscall_nr_reboot = 142; + syscall_nr_setregid = 143; + syscall_nr_setgid = 144; + syscall_nr_setreuid = 145; + syscall_nr_setuid = 146; + syscall_nr_setresuid = 147; + syscall_nr_getresuid = 148; + syscall_nr_setresgid = 149; + syscall_nr_getresgid = 150; + syscall_nr_setfsuid = 151; + syscall_nr_setfsgid = 152; + syscall_nr_times = 153; + syscall_nr_setpgid = 154; + syscall_nr_getpgid = 155; + syscall_nr_getsid = 156; + syscall_nr_setsid = 157; + syscall_nr_getgroups = 158; + syscall_nr_setgroups = 159; + syscall_nr_uname = 160; + syscall_nr_sethostname = 161; + syscall_nr_setdomainname = 162; + syscall_nr_getrlimit = 163; + syscall_nr_setrlimit = 164; + syscall_nr_getrusage = 165; + syscall_nr_umask = 166; + syscall_nr_prctl = 167; + syscall_nr_getcpu = 168; + syscall_nr_gettimeofday = 169; + syscall_nr_settimeofday = 170; + syscall_nr_adjtimex = 171; + syscall_nr_getpid = 172; + syscall_nr_getppid = 173; + syscall_nr_getuid = 174; + syscall_nr_geteuid = 175; + syscall_nr_getgid = 176; + syscall_nr_getegid = 177; + syscall_nr_gettid = 178; + syscall_nr_sysinfo = 179; + syscall_nr_mq_open = 180; + syscall_nr_mq_unlink = 181; + syscall_nr_mq_timedsend = 182; + syscall_nr_mq_timedreceive = 183; + syscall_nr_mq_notify = 184; + syscall_nr_mq_getsetattr = 185; + syscall_nr_msgget = 186; + syscall_nr_msgctl = 187; + syscall_nr_msgrcv = 188; + syscall_nr_msgsnd = 189; + syscall_nr_semget = 190; + syscall_nr_semctl = 191; + syscall_nr_semtimedop = 192; + syscall_nr_semop = 193; + syscall_nr_shmget = 194; + syscall_nr_shmctl = 195; + syscall_nr_shmat = 196; + syscall_nr_shmdt = 197; + syscall_nr_socket = 198; + syscall_nr_socketpair = 199; + syscall_nr_bind = 200; + syscall_nr_listen = 201; + syscall_nr_accept = 202; + syscall_nr_connect = 203; + syscall_nr_getsockname = 204; + syscall_nr_getpeername = 205; + syscall_nr_sendto = 206; + syscall_nr_recvfrom = 207; + syscall_nr_setsockopt = 208; + syscall_nr_getsockopt = 209; + syscall_nr_shutdown = 210; + syscall_nr_sendmsg = 211; + syscall_nr_recvmsg = 212; + syscall_nr_readahead = 213; + syscall_nr_brk = 214; + syscall_nr_munmap = 215; + syscall_nr_mremap = 216; + syscall_nr_add_key = 217; + syscall_nr_request_key = 218; + syscall_nr_keyctl = 219; + syscall_nr_clone = 220; + syscall_nr_execve = 221; + syscall_nr_mmap = 222; + syscall_nr_fadvise64 = 223; + syscall_nr_swapon = 224; + syscall_nr_swapoff = 225; + syscall_nr_mprotect = 226; + syscall_nr_msync = 227; + syscall_nr_mlock = 228; + syscall_nr_munlock = 229; + syscall_nr_mlockall = 230; + syscall_nr_munlockall = 231; + syscall_nr_mincore = 232; + syscall_nr_madvise = 233; + syscall_nr_remap_file_pages = 234; + syscall_nr_mbind = 235; + syscall_nr_get_mempolicy = 236; + syscall_nr_set_mempolicy = 237; + syscall_nr_migrate_pages = 238; + syscall_nr_move_pages = 239; + syscall_nr_rt_tgsigqueueinfo = 240; + syscall_nr_perf_event_open = 241; + syscall_nr_accept4 = 242; + syscall_nr_recvmmsg = 243; + syscall_nr_arch_specific_syscall = 244; + + syscall_nr_wait4 = 260; + syscall_nr_prlimit64 = 261; + syscall_nr_fanotify_init = 262; + syscall_nr_fanotify_mark = 263; + syscall_nr_name_to_handle_at = 264; + syscall_nr_open_by_handle_at = 265; + syscall_nr_clock_adjtime = 266; + syscall_nr_syncfs = 267; + syscall_nr_setns = 268; + syscall_nr_sendmmsg = 269; + syscall_nr_process_vm_readv = 270; + syscall_nr_process_vm_writev = 271; + syscall_nr_kcmp = 272; + syscall_nr_finit_module = 273; + syscall_nr_sched_setattr = 274; + syscall_nr_sched_getattr = 275; + syscall_nr_renameat2 = 276; + syscall_nr_seccomp = 277; + syscall_nr_getrandom = 278; + syscall_nr_memfd_create = 279; + syscall_nr_bpf = 280; + syscall_nr_execveat = 281; + syscall_nr_syscalls = 282; diff --git a/fpcsrc/rtl/linux/sysosh.inc b/fpcsrc/rtl/linux/sysosh.inc index ee0cf0a8..62d5f2d5 100644 --- a/fpcsrc/rtl/linux/sysosh.inc +++ b/fpcsrc/rtl/linux/sysosh.inc @@ -23,18 +23,12 @@ type { pthread_t is defined as an "unsigned long" } TThreadID = PtrUInt; - { pthread_mutex_t } PRTLCriticalSection = ^TRTLCriticalSection; - TRTLCriticalSection = record - __m_reserved: longint; - __m_count: longint; - __m_owner: pointer; - __m_kind: longint; - __m_lock: record - __status: sizeint; - __spinlock: longint; - end; - end; +{$macro on} +{$define MUTEXTYPENAME := TRTLCriticalSection} +{$i pmutext.inc} +{$undef MUTEXTYPENAME} +{$macro off} diff --git a/fpcsrc/rtl/linux/termios.inc b/fpcsrc/rtl/linux/termios.inc index 78cfb03b..7554839b 100644 --- a/fpcsrc/rtl/linux/termios.inc +++ b/fpcsrc/rtl/linux/termios.inc @@ -22,6 +22,271 @@ Const NCCS = 32; NCC = 8; +{$ifdef cpuaarch64} + +{ from Linux 4.0, include/uapi/asm-generic/ioctls.h } + + { For Terminal handling } + TCGETS = $5401; + TCSETS = $5402; + TCSETSW = $5403; + TCSETSF = $5404; + TCGETA = $5405; + TCSETA = $5406; + TCSETAW = $5407; + TCSETAF = $5408; + TCSBRK = $5409; + TCXONC = $540A; + TCFLSH = $540B; + TIOCEXCL = $540C; + TIOCNXCL = $540D; + TIOCSCTTY = $540E; + TIOCGPGRP = $540F; + TIOCSPGRP = $5410; + TIOCOUTQ = $5411; + TIOCSTI = $5412; + TIOCGWINSZ = $5413; + TIOCSWINSZ = $5414; + TIOCMGET = $5415; + TIOCMBIS = $5416; + TIOCMBIC = $5417; + TIOCMSET = $5418; + TIOCGSOFTCAR = $5419; + TIOCSSOFTCAR = $541A; + FIONREAD = $541B; + TIOCINQ = FIONREAD; + TIOCLINUX = $541C; + TIOCCONS = $541D; + TIOCGSERIAL = $541E; + TIOCSSERIAL = $541F; + TIOCPKT = $5420; + FIONBIO = $5421; + TIOCNOTTY = $5422; + TIOCSETD = $5423; + TIOCGETD = $5424; + TCSBRKP = $5425; + + TIOCSBRK = $5427; + TIOCCBRK = $5428; + TIOCGSID = $5429; + + TIOCGRS485 = $542E; + TIOCSRS485 = $542F; + + TCGETX = $5432; + TCSETX = $5433; + TCSETXF = $5434; + TCSETXW = $5435; + TIOCVHANGUP = $5437; + + FIONCLEX = $5450; + FIOCLEX = $5451; + FIOASYNC = $5452; + TIOCSERCONFIG = $5453; + TIOCSERGWILD = $5454; + TIOCSERSWILD = $5455; + TIOCGLCKTRMIOS = $5456; + TIOCSLCKTRMIOS = $5457; + TIOCSERGSTRUCT = $5458; + TIOCSERGETLSR = $5459; + TIOCSERGETMULTI = $545A; + TIOCSERSETMULTI = $545B; + TIOCMIWAIT = $545C; + TIOCGICOUNT = $545D; + + FIOQSIZE = $5460; + + TIOCPKT_DATA = 0; + TIOCPKT_FLUSHREAD = 1; + TIOCPKT_FLUSHWRITE = 2; + TIOCPKT_STOP = 4; + TIOCPKT_START = 8; + TIOCPKT_NOSTOP = 16; + TIOCPKT_DOSTOP = 32; + TIOCPKT_IOCTL = 64; + + TIOCSER_TEMT = $01; + +{ from Linux 4.0, include/uapi/asm-generic/termbits.h } + + { c_cc characters } + VINTR = 0; + VQUIT = 1; + VERASE = 2; + VKILL = 3; + VEOF = 4; + VTIME = 5; + VMIN = 6; + VSWTC = 7; + VSTART = 8; + VSTOP = 9; + VSUSP = 10; + VEOL = 11; + VREPRINT = 12; + VDISCARD = 13; + VWERASE = 14; + VLNEXT = 15; + VEOL2 = 16; + + { c_iflag bits } + IGNBRK = &0000001; + BRKINT = &0000002; + IGNPAR = &0000004; + PARMRK = &0000010; + INPCK = &0000020; + ISTRIP = &0000040; + INLCR = &0000100; + IGNCR = &0000200; + ICRNL = &0000400; + IUCLC = &0001000; + IXON = &0002000; + IXANY = &0004000; + IXOFF = &0010000; + IMAXBEL = &0020000; + IUTF8 = &0040000; + + { c_oflag bits } + OPOST = &0000001; + OLCUC = &0000002; + ONLCR = &0000004; + OCRNL = &0000010; + ONOCR = &0000020; + ONLRET = &0000040; + OFILL = &0000100; + OFDEL = &0000200; + NLDLY = &0000400; + NL0 = &0000000; + NL1 = &0000400; + CRDLY = &0003000; + CR0 = &0000000; + CR1 = &0001000; + CR2 = &0002000; + CR3 = &0003000; + TABDLY = &0014000; + TAB0 = &0000000; + TAB1 = &0004000; + TAB2 = &0010000; + TAB3 = &0014000; + XTABS = &0014000; + BSDLY = &0020000; + BS0 = &0000000; + BS1 = &0020000; + VTDLY = &0040000; + VT0 = &0000000; + VT1 = &0040000; + FFDLY = &0100000; + FF0 = &0000000; + FF1 = &0100000; + + { c_cflag bits } + CBAUD = &0010017; + B0 = &0000000; + B50 = &0000001; + B75 = &0000002; + B110 = &0000003; + B134 = &0000004; + B150 = &0000005; + B200 = &0000006; + B300 = &0000007; + B600 = &0000010; + B1200 = &0000011; + B1800 = &0000012; + B2400 = &0000013; + B4800 = &0000014; + B9600 = &0000015; + B19200 = &0000016; + B38400 = &0000017; + EXTA = B19200; + EXTB = B38400; + CSIZE = &0000060; + CS5 = &0000000; + CS6 = &0000020; + CS7 = &0000040; + CS8 = &0000060; + CSTOPB = &0000100; + CREAD = &0000200; + PARENB = &0000400; + PARODD = &0001000; + HUPCL = &0002000; + CLOCAL = &0004000; + CBAUDEX = &0010000; + BOTHER = &0010000; + B57600 = &0010001; + B115200 = &0010002; + B230400 = &0010003; + B460800 = &0010004; + B500000 = &0010005; + B576000 = &0010006; + B921600 = &0010007; + B1000000 = &0010010; + B1152000 = &0010011; + B1500000 = &0010012; + B2000000 = &0010013; + B2500000 = &0010014; + B3000000 = &0010015; + B3500000 = &0010016; + B4000000 = &0010017; + + CIBAUD = &002003600000; + CMSPAR = &010000000000; + CRTSCTS = &020000000000; + + IBSHIFT = 16; + + { c_lflag bits } + ISIG = &0000001; + ICANON = &0000002; + XCASE = &0000004; + ECHO = &0000010; + ECHOE = &0000020; + ECHOK = &0000040; + ECHONL = &0000100; + NOFLSH = &0000200; + TOSTOP = &0000400; + ECHOCTL = &0001000; + ECHOPRT = &0002000; + ECHOKE = &0004000; + FLUSHO = &0010000; + PENDIN = &0040000; + IEXTEN = &0100000; + EXTPROC = &0200000; + + { TCFlow } + TCOOFF = 0; + TCOON = 1; + TCIOFF = 2; + TCION = 3; + + { TCFlush } + TCIFLUSH = 0; + TCOFLUSH = 1; + TCIOFLUSH = 2; + + { TCSetAttr } + TCSANOW = 0; + TCSADRAIN = 1; + TCSAFLUSH = 2; + +{ from Linux 4.0, include/uapi/asm-generic/termios.h } + + { c_line bits } + TIOCM_LE = $001; + TIOCM_DTR = $002; + TIOCM_RTS = $004; + TIOCM_ST = $008; + TIOCM_SR = $010; + TIOCM_CTS = $020; + TIOCM_CAR = $040; + TIOCM_RNG = $080; + TIOCM_DSR = $100; + TIOCM_CD = TIOCM_CAR; + TIOCM_RI = TIOCM_RNG; + TIOCM_OUT1 = $2000; + TIOCM_OUT2 = $4000; + TIOCM_LOOP = $8000; + +{$endif cpuaarch64} + {$ifdef cpupowerpc} TCGETS = $402c7413; TCSETS = $802c7414; diff --git a/fpcsrc/rtl/unix/cthreads.pp b/fpcsrc/rtl/unix/cthreads.pp index e088f19d..2089f310 100644 --- a/fpcsrc/rtl/unix/cthreads.pp +++ b/fpcsrc/rtl/unix/cthreads.pp @@ -140,6 +140,10 @@ Type PINTRTLEvent = ^TINTRTLEvent; threadvarblocksize:=align(threadvarblocksize,16); {$endif cpupowerpc64} + {$ifdef cpuaarch64} + threadvarblocksize:=align(threadvarblocksize,16); + {$endif cpuaarch64} + offset:=threadvarblocksize; inc(threadvarblocksize,size); diff --git a/fpcsrc/rtl/unix/cwstring.pp b/fpcsrc/rtl/unix/cwstring.pp index fa640560..c9068c50 100644 --- a/fpcsrc/rtl/unix/cwstring.pp +++ b/fpcsrc/rtl/unix/cwstring.pp @@ -230,12 +230,12 @@ procedure InitThread; var transliterate: cint; iconvindex: longint; -{$if not(defined(darwin) and defined(cpuarm)) and not defined(iphonesim)} +{$if not(defined(darwin) and (defined(cpuarm) or defined(cpuaarch64))) and not defined(iphonesim)} iconvname: rawbytestring; {$endif} begin current_DefaultSystemCodePage:=DefaultSystemCodePage; -{$if not(defined(darwin) and defined(cpuarm)) and not defined(iphonesim)} +{$if not(defined(darwin) and (defined(cpuarm) or defined(cpuaarch64))) and not defined(iphonesim)} iconvindex:=GetCodepageData(DefaultSystemCodePage); if iconvindex<>-1 then iconvname:=UnixCpMap[iconvindex].name diff --git a/fpcsrc/utils/fpcm/fpcmmain.pp b/fpcsrc/utils/fpcm/fpcmmain.pp index 5facea51..86aa6199 100644 --- a/fpcsrc/utils/fpcm/fpcmmain.pp +++ b/fpcsrc/utils/fpcm/fpcmmain.pp @@ -67,7 +67,7 @@ interface type TCpu=( - c_i386,c_m68k,c_powerpc,c_sparc,c_x86_64,c_arm,c_powerpc64,c_avr,c_armeb,c_armel,c_mips,c_mipsel,c_mips64,c_mips64el,c_jvm,c_i8086 + c_i386,c_m68k,c_powerpc,c_sparc,c_x86_64,c_arm,c_powerpc64,c_avr,c_armeb,c_armel,c_mips,c_mipsel,c_mips64,c_mips64el,c_jvm,c_i8086,c_aarch64 ); TOS=( @@ -82,15 +82,15 @@ interface const CpuStr : array[TCpu] of string=( - 'i386','m68k','powerpc','sparc','x86_64','arm','powerpc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','i8086' + 'i386','m68k','powerpc','sparc','x86_64','arm','powerpc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','i8086','aarch64' ); CpuSuffix : array[TCpu] of string=( - '_i386','_m68k','_powerpc','_sparc','_x86_64','_arm','_powerpc64','_avr','_armeb', '_armel', '_mips', '_mipsel', '_mips64', '_mips64el', '_jvm','_i8086' + '_i386','_m68k','_powerpc','_sparc','_x86_64','_arm','_powerpc64','_avr','_armeb', '_armel', '_mips', '_mipsel', '_mips64', '_mips64el', '_jvm','_i8086','_aarch64' ); ppcSuffix : array[TCpu] of string=( - '386','m68k','ppc','sparc','x86_64','arm','ppc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','8086' + '386','m68k','ppc','sparc','x64','arm','ppc64','avr','armeb', 'armel', 'mips', 'mipsel', 'mips64', 'mips64el', 'jvm','8086','aarch64' ); OSStr : array[TOS] of string=( @@ -113,44 +113,44 @@ interface { This table is kept OS,Cpu because it is easier to maintain (PFV) } OSCpuPossible : array[TOS,TCpu] of boolean = ( - { os i386 m68k ppc sparc x86_64 arm ppc64 avr armeb armel mips mipsel mips64 misp64el jvm i8086 } - { linux } ( true, true, true, true, true, true, true, false, true, false, true, true, false, false, false, false), - { go32v2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { win32 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { os2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { freebsd } ( true, true, false, false, true, false, false, false, false, false, false, false, false, false, false, false), - { beos } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { haiku } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { netbsd } ( true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false), - { amiga } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { atari } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { solaris } ( true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false), - { qnx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { netware } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { openbsd } ( true, true, false, false, true, false, false, false, false, false, false, false, false, false, false, false), - { wdosx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { palmos } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { macos } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { darwin } ( true, false, true, false, true, true, true, false, false, false, false, false, false, false, false, false), - { emx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { watcom } ( true, false, false, false ,false, false, false, false, false, false, false, false, false, false, false, false), - { morphos } ( false, false, true, false ,false, false, false, false, false, false, false, false, false, false, false, false), - { netwlibc }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { win64 } ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), - { wince }( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { gba } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { nds } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { embedded }( true, true, true, true, true, true, true, true, true , false, false, true , false, false, false, false), - { symbian } ( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false), - { nativent }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { iphonesim }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - { wii } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false), - { aix } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false), - { java } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false), - { android } ( true, false, false, false, false, true, false, false, false, false, false, true, false, false, true, false), - { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true), - { aros } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), - {dragonfly} ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false) + { os i386 m68k ppc sparc x86_64 arm ppc64 avr armeb armel mips mipsel mips64 misp64el jvm i8086 aarch64} + { linux } ( true, true, true, true, true, true, true, false, true, false, true, true, false, false, false, false, true ), + { go32v2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win32 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { os2 } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { freebsd } ( true, true, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), + { beos } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { haiku } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netbsd } ( true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false, false), + { amiga } ( false, true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { atari } ( false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { solaris } ( true, false, false, true, true, false, false, false, false, false, false, false, false, false, false, false, false), + { qnx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { netware } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { openbsd } ( true, true, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), + { wdosx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { palmos } ( false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { macos } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { darwin } ( true, false, true, false, true, true, true, false, false, false, false, false, false, false, false, false, true ), + { emx } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { watcom } ( true, false, false, false ,false, false, false, false, false, false, false, false, false, false, false, false, false), + { morphos } ( false, false, true, false ,false, false, false, false, false, false, false, false, false, false, false, false, false), + { netwlibc }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { win64 } ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), + { wince }( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { gba } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { nds } ( false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { embedded }( true, true, true, true, true, true, true, true, true , false, false, true , false, false, false, false, false), + { symbian } ( true, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false), + { nativent }( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { iphonesim }( true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false), + { wii } ( false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + { aix } ( false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false), + { java } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false), + { android } ( true, false, false, false, false, true, false, false, false, false, false, true, false, false, true, false, false), + { msdos } ( false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true , false), + { aros } ( true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false), + {dragonfly} ( false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false) ); type diff --git a/fpcsrc/utils/fpcres/fpcres.pas b/fpcsrc/utils/fpcres/fpcres.pas index bdaddc81..83775e2f 100644 --- a/fpcsrc/utils/fpcres/fpcres.pas +++ b/fpcsrc/utils/fpcres/fpcres.pas @@ -73,7 +73,7 @@ begin writeln(' i386, x86_64, arm (coff)'); writeln(' i386, x86_64, powerpc, powerpc64, arm, armeb, m68k,'); writeln(' sparc, alpha, ia64, mips, mipsel (elf)'); - writeln(' i386, x86_64, powerpc, powerpc64, arm (mach-o)'); + writeln(' i386, x86_64, powerpc, powerpc64, arm, aarch64 (mach-o)'); writeln(' bigendian, littleendian (external)'); writeln(' --subarch, -s Set object file sub-architecture. Supported values:'); writeln(' arm: all, v4t, v6, v5tej, xscale, v7'); @@ -252,6 +252,7 @@ begin mtia64 : Result.MachineType:=emtia64; mtmips : Result.MachineType:=emtmips; mtmipsel : Result.MachineType:=emtmipsel; + mtaarch64 : Result.MachineType:=emtaarch64; end; end; @@ -312,6 +313,11 @@ begin Result.MachineType:=mmtarm; MachOSubMachineType.fArmSubType:=ArmSubMachine2MachOSubMachine[CurrentTarget.submachine.subarm]; end; + mtaarch64 : + begin + Result.MachineType:=mmtarm64; + MachOSubMachineType.fArm64SubType:=msmaarch64_all; + end; end; Result.SubMachineType:=MachOSubMachineType; end; diff --git a/fpcsrc/utils/fpcres/target.pas b/fpcsrc/utils/fpcres/target.pas index 7d5340c1..0e1964a8 100644 --- a/fpcsrc/utils/fpcres/target.pas +++ b/fpcsrc/utils/fpcres/target.pas @@ -22,7 +22,7 @@ interface type TMachineType = (mtnone, mti386,mtx86_64,mtppc,mtppc64,mtarm,mtarmeb,mtm68k, - mtsparc,mtalpha,mtia64,mtmips,mtmipsel, + mtsparc,mtalpha,mtia64,mtmips,mtmipsel,mtaarch64, mtBigEndian,mtLittleEndian); TMachineTypes = set of TMachineType; @@ -34,7 +34,7 @@ type mtarm,mtarmeb: (subarm: TSubMachineTypeArm); mtnone, mti386,mtx86_64,mtppc,mtppc64,mtm68k, - mtsparc,mtalpha,mtia64,mtmips,mtmipsel, + mtsparc,mtalpha,mtia64,mtmips,mtmipsel,mtaarch64, mtBigEndian,mtLittleEndian: (subgen: TSubMachineTypeGeneric); end; @@ -83,6 +83,7 @@ var (name : 'ia64'; formats : [ofElf]), //mtia64 (name : 'mips'; formats : [ofElf]; alias : 'mipseb'), //mtmips (name : 'mipsel'; formats : [ofElf]), //mtmipsel + (name : 'aarch64'; formats : [ofElf, ofMachO]), //mtaarch64 (name : 'bigendian'; formats : [ofExt]), //mtBigEndian (name : 'littleendian'; formats : [ofExt]) //mtLittleEndian ); @@ -99,35 +100,31 @@ var (name : 'elf'; ext : '.or'; machines : [mti386,mtx86_64,mtppc, mtppc64,mtarm,mtarmeb, mtm68k,mtsparc,mtalpha, - mtia64,mtmips,mtmipsel]), + mtaarch64]), (name : 'coff'; ext : '.o'; machines : [mti386,mtx86_64,mtarm, mtppc,mtppc64]), (name : 'xcoff'; ext : '.o'; machines : [mtppc{,mtppc64}]), (name : 'mach-o'; ext : '.or'; machines : [mti386,mtx86_64,mtppc, - mtppc64,mtarm]), + mtppc64,mtarm,mtaarch64]), (name : 'external'; ext : '.fpcres'; machines : [mtBigEndian,mtLittleEndian]) ); CurrentTarget : TResTarget = ( - {$IFDEF CPUI386} + {$if defined(CPUI386)} machine : mti386; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUX86_64} + {$elseif defined(CPUX86_64)} machine : mtx86_64; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUPOWERPC32} + {$elseif defined(CPUPOWERPC32)} machine : mtppc; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUPOWERPC64} + {$elseif defined(CPUPOWERPC64)} machine : mtppc64; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUARM} + {$elseif defined(CPUARM)} {$IFDEF ENDIAN_LITTLE} machine : mtarm; submachine : (subarm: smtarm_all); @@ -135,44 +132,31 @@ var machine : mtarmeb; submachine : (subarm: smtarm_all); {$ENDIF} - {$ELSE} - {$IFDEF CPU68K} + {$elseif defined(CPU68K)} machine : mtm68k; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUSPARC} + {$elseif defined(CPUSPARC)} machine : mtsparc; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUALPHA} + {$elseif defined(CPUALPHA)} machine : mtalpha; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUIA64} + {$elseif defined(CPUIA64)} machine : mtia64; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUMIPSEL} + {$elseif defined(CPUMIPSEL)} machine : mtmipsel; submachine : (subgen: smtgen_all); - {$ELSE} - {$IFDEF CPUMIPS} + {$elseif defined(CPUMIPS)} machine : mtmips; submachine : (subgen: smtgen_all); - {$ELSE} + {$elseif defined(CPUAARCH64)} + machine : mtaarch64; + submachine : (subgen: smtgen_all); + {$else} machine : mti386; //default i386 submachine : (subgen: smtgen_all); - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} - {$ENDIF} + {$endif} {$IFDEF WINDOWS} objformat : ofCoff; -- 2.30.2