--- /dev/null
+Description: Upstream includes in svn already arm64 support
+ This patch was created with a recipe from bug 784569 + minor changes by Elbrus:
+ mkdir a b
+ wget ftp://ftp.freepascal.org/pub/fpc/beta/3.0.0-rc2/source/fpcbuild-3.0.0rc2.tar.gz
+ tar xzf fpcbuild-3.0.0rc2.tar.gz -C a --strip-components=1
+ svn export -r 32015 http://svn.freepascal.org/svn/fpc/branches/fixes_3_0_ios b/fpcsrc
+ .
+ find [ab]/fpcsrc -name Makefile -delete
+ find [ab]/fpcsrc -name '*.[ao]' -o -name '*.exe' -delete
+
+ ( cd b && ../a/install/updfpmkver 3.0.0rc2 )
+ ( cd b && ../a/install/updmkver 3.0.0rc2 true )
+ cp -rT [ab]/fpcsrc/installer
+ cp -rT [ab]/fpcsrc/packages/chm
+ perl -i -pe "s/(patch_nr\s*=\s*)'.*'/\$1'0'/;" b/fpcsrc/compiler/version.pas
+ perl -i -pe "s/(minorpatch\s*=\s*)'.*'/\$1'rc2'/;" b/fpcsrc/compiler/version.pas
+ .
+ # delete directories univint and tests
+ .
+ git diff --no-prefix [ab]/fpcsrc > add-arm64-support.patch
+ .
+ # apply on top of full debian patches + quilt refresh
+ .
+ .
+ This patch was updated manually by elbrus upon merging 3.0.2 which should
+ contain support for AArch64, but too much of the patch still applied cleanly.
+Author: Edmund Grimley Evans <edmund.grimley.evans@gmail.com>
+Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=784569
+
+Index: fpc/fpcsrc/Makefile.fpc
+===================================================================
+--- fpc.orig/fpcsrc/Makefile.fpc
++++ fpc/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)
+Index: fpc/fpcsrc/compiler/Makefile.fpc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/Makefile.fpc
++++ fpc/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)
+Index: fpc/fpcsrc/compiler/aarch64/a64att.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64att.inc
++++ fpc/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'
+ );
+Index: fpc/fpcsrc/compiler/aarch64/a64atts.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64atts.inc
++++ fpc/fpcsrc/compiler/aarch64/a64atts.inc
+@@ -1,8 +1,65 @@
+-{ don't edit, this file is generated from armins.dat }
++{ don't edit, this file is generated from a64ins.dat }
+ (
+ 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,
+ attsufNONE,
+Index: fpc/fpcsrc/compiler/aarch64/a64ins.dat
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64ins.dat
++++ fpc/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]
+Index: fpc/fpcsrc/compiler/aarch64/a64op.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64op.inc
++++ fpc/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
+ );
+Index: fpc/fpcsrc/compiler/aarch64/a64reg.dat
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64reg.dat
++++ fpc/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
+Index: fpc/fpcsrc/compiler/aarch64/a64tab.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/a64tab.inc
++++ fpc/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 }
+ (
+
+ );
+Index: fpc/fpcsrc/compiler/aarch64/aasmcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/aasmcpu.pas
++++ fpc/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,<shift>Rs
+- case 6: // AND Rd,Rn,Rm,<shift>imm
+- case 7: // AND Rd,Rn,<shift>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]
+- }
+- // <shift>
+- 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,<shift>Rs
+- case 0xA: // MOV Rd,Rm,<shift>imm
+- case 0xB: // MOV Rd,<shift>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]
+- }
+- // <shift>
+- 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,<shift>Rs
+- case 0xE: // CMP Rn,Rm,<shift>imm
+- case 0xF: // CMP Rn,<shift>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]
+- }
+- // <shift>
+- 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,<psr>
+- ++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 <psr>,Rm
+- case 0x12: // MSR <psrf>,Rm
+- case 0x13: // MSR <psrf>,#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.
+Index: fpc/fpcsrc/compiler/aarch64/agcpugas.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/aoptcpub.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/aoptcpub.pas
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/cgcpu.pas
+===================================================================
+--- /dev/null
++++ fpc/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 ((shift<tcgsize2size[size]*(8 div 2)) and
++ (word(a)<>0) 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
++ begin
++ a_load_reg_ref_unaligned(list,fromsize,tosize,reg,ref);
++ end
++ else
++ begin
++ case tosize of
++ { signed integer registers }
++ OS_8,
++ OS_S8:
++ oppostfix:=PF_B;
++ OS_16,
++ OS_S16:
++ oppostfix:=PF_H;
++ OS_32,
++ OS_S32,
++ OS_64,
++ OS_S64:
++ oppostfix:=PF_None;
++ else
++ InternalError(200308299);
++ end;
++ handle_load_store(list,A_STR,tosize,oppostfix,reg,ref);
++ end;
++ end;
++
++
++ procedure tcgaarch64.a_load_ref_reg(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; reg: tregister);
++ var
++ oppostfix:toppostfix;
++ begin
++ if tcgsize2Size[fromsize]>=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<tcgsize2size[fromsize]) then
++ begin
++ a_load_ref_reg_unaligned(list,fromsize,tosize,ref,reg);
++ exit;
++ end;
++ case fromsize of
++ { signed integer registers }
++ OS_8:
++ oppostfix:=PF_B;
++ OS_S8:
++ oppostfix:=PF_SB;
++ OS_16:
++ oppostfix:=PF_H;
++ OS_S16:
++ oppostfix:=PF_SH;
++ OS_S32:
++ if getsubreg(reg)=R_SUBD then
++ oppostfix:=PF_NONE
++ else
++ oppostfix:=PF_SW;
++ OS_32,
++ OS_64,
++ OS_S64:
++ oppostfix:=PF_None;
++ else
++ InternalError(200308297);
++ end;
++ handle_load_store(list,A_LDR,fromsize,oppostfix,reg,ref);
++
++ { clear upper 16 bits if the value was negative }
++ if (fromsize=OS_S8) and (tosize=OS_16) then
++ a_load_reg_reg(list,fromsize,tosize,reg,reg);
++ end;
++
++
++ procedure tcgaarch64.a_load_ref_reg_unaligned(list: TAsmList; fromsize, tosize: tcgsize; const ref: treference; register: tregister);
++ var
++ href: treference;
++ hreg1, hreg2, tmpreg: tregister;
++ begin
++ if fromsize in [OS_64,OS_S64] then
++ begin
++ { split into two 32 bit loads }
++ hreg1:=makeregsize(register,OS_32);
++ hreg2:=getintregister(list,OS_32);
++ if target_info.endian=endian_big then
++ begin
++ tmpreg:=hreg1;
++ hreg1:=hreg2;
++ hreg2:=tmpreg;
++ end;
++ { can we use LDP? }
++ if (ref.alignment=4) and
++ (simple_ref_type(A_LDP,OS_32,PF_None,ref)=sr_simple) then
++ list.concat(taicpu.op_reg_reg_ref(A_LDP,hreg1,hreg2,ref))
++ else
++ begin
++ a_load_ref_reg(list,OS_32,OS_32,ref,hreg1);
++ href:=ref;
++ inc(href.offset,4);
++ a_load_ref_reg(list,OS_32,OS_32,href,hreg2);
++ end;
++ list.concat(taicpu.op_reg_reg_const_const(A_BFI,register,makeregsize(hreg2,OS_64),32,32));
++ end
++ else
++ inherited;
++ end;
++
++
++ procedure tcgaarch64.a_load_reg_reg(list:TAsmList;fromsize,tosize:tcgsize;reg1,reg2:tregister);
++ var
++ instr: taicpu;
++ begin
++ { we use both 32 and 64 bit registers -> 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.
+Index: fpc/fpcsrc/compiler/aarch64/cpubase.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/cpubase.pas
++++ fpc/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 <patternlen> 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 (rightmostone<patternlen) and
++ (rightmostzero<patternlen) then
++ begin
++ if rightmostone>rightmostzero 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<patternlen then
++ begin
++ secondrightmostbit:=BsfQWord(not(checkpattern) shr secondrightmostbit)+secondrightmostbit;
++ if secondrightmostbit<patternlen then
++ exit;
++ end;
++ { ok, this is a valid pattern, now does d consist of a
++ repetition of this pattern? }
++ replicatedlen:=patternlen;
++ checkpattern:=pattern;
++ while replicatedlen<maxbits do
++ begin
++ { douplicate current pattern }
++ checkpattern:=checkpattern or (checkpattern shl replicatedlen);
++ replicatedlen:=replicatedlen*2;
++ end;
++ if qword(d)=checkpattern then
++ begin
++ { yes! }
++ result:=true;
++ exit;
++ end;
++ end;
++ patternlen:=patternlen*2;
++ end;
++ end;
++
+ end.
+Index: fpc/fpcsrc/compiler/aarch64/cpuinfo.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/cpuinfo.pas
++++ fpc/fpcsrc/compiler/aarch64/cpuinfo.pas
+@@ -103,12 +103,12 @@ Const
+ { no need to write info about those }
+ [cs_opt_level1,cs_opt_level2,cs_opt_level3]+
+ [cs_opt_regvar,cs_opt_loopunroll,cs_opt_tailrecursion,
+- cs_opt_stackframe,cs_opt_nodecse,cs_opt_reorder_fields,cs_opt_fastmath];
++ cs_opt_nodecse,cs_opt_reorder_fields,cs_opt_fastmath];
+
+ level1optimizerswitches = genericlevel1optimizerswitches;
+ level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches +
+ [cs_opt_regvar,cs_opt_stackframe,cs_opt_tailrecursion,cs_opt_nodecse];
+- level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [cs_opt_scheduler{,cs_opt_loopunroll}];
++ level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+ level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [];
+
+ Implementation
+Index: fpc/fpcsrc/compiler/aarch64/cpunode.pas
+===================================================================
+--- /dev/null
++++ fpc/fpcsrc/compiler/aarch64/cpunode.pas
+@@ -0,0 +1,40 @@
++{******************************************************************************
++ Copyright (c) 2014 by Florian Klaempfl
++
++ Includes the aarch64 code generator
++
++ This program is free software; you can redistribute it and/or modify
++ it under the terms of the GNU General Public License as published by
++ the Free Software Foundation; either version 2 of the License, or
++ (at your option) any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ GNU General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++ *****************************************************************************}
++unit cpunode;
++
++{$I fpcdefs.inc}
++
++interface
++{ This unit is used to define the specific CPU implementations. All needed
++actions are included in the INITALIZATION part of these units. This explains
++the behaviour of such a unit having just a USES clause! }
++
++implementation
++
++ uses
++ ncgbas,ncgflw,ncgcal,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,ncgobjc,
++ ncpuadd,ncpumat,ncpumem,ncpuinl,ncpucnv,ncpuset,
++ { this not really a node }
++ rgcpu,
++ { symtable }
++ symcpu;
++
++end.
+Index: fpc/fpcsrc/compiler/aarch64/cpupara.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/cpupara.pas
++++ fpc/fpcsrc/compiler/aarch64/cpupara.pas
+@@ -1,5 +1,5 @@
+ {
+- Copyright (c) 2003-2012 by Florian Klaempfl and others
++ Copyright (c) 2013-2014 by Jonas Maebe, Florian Klaempfl and others
+
+ AArch64 specific calling conventions
+
+@@ -34,19 +34,24 @@ unit cpupara;
+
+ type
+ taarch64paramanager = class(tparamanager)
+- function get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;override;
+- function get_volatile_registers_fpu(calloption : tproccalloption):tcpuregisterset;override;
+- function get_volatile_registers_mm(calloption : tproccalloption):tcpuregisterset;override;
+- function push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
+- function ret_in_param(def:tdef;pd:tabstractprocdef):boolean;override;
+- procedure getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);override;
+- function create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;override;
+- function create_varargs_paraloc_info(p : tabstractprocdef; varargspara:tvarargsparalist):longint;override;
+- function get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
++ function get_volatile_registers_int(calloption: tproccalloption): tcpuregisterset; override;
++ function get_volatile_registers_fpu(calloption: tproccalloption): tcpuregisterset; override;
++ function get_volatile_registers_mm(calloption: tproccalloption): tcpuregisterset; override;
++ function push_addr_param(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
++ function ret_in_param(def: tdef; pd: tabstractprocdef):boolean;override;
++ function create_paraloc_info(p: tabstractprocdef; side: tcallercallee):longint;override;
++ function create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;override;
++ function get_funcretloc(p: tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
++ function param_use_paraloc(const cgpara: tcgpara): boolean; override;
+ private
+- procedure init_values(var curintreg, curfloatreg, curmmreg: tsuperregister; var cur_stack_offset: aword; var sparesinglereg: tregister);
+- function 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;
++ curintreg,
++ curmmreg: tsuperregister;
++ curstackoffset: aword;
++
++ procedure init_para_alloc_values;
++ procedure alloc_para(out result: tcgpara; p: tabstractprocdef; varspez: tvarspez; side: tcallercallee; paradef: tdef; isvariadic, isdelphinestedcc: boolean);
++
++ procedure create_paraloc_info_intern(p: tabstractprocdef; side: tcallercallee; paras: tparalist; isvariadic: boolean);
+ end;
+
+ implementation
+@@ -56,6 +61,13 @@ unit cpupara;
+ rgobj,
+ defutil,symsym,symtable;
+
++ const
++ RS_FIRST_INT_PARAM_SUPREG = RS_X0;
++ RS_LAST_INT_PARAM_SUPREG = RS_X7;
++ { Q0/D0/S0/H0/B0 all have the same superregister number }
++ RS_FIRST_MM_PARAM_SUPREG = RS_D0;
++ RS_LAST_MM_PARAM_SUPREG = RS_D7;
++
+
+ function taarch64paramanager.get_volatile_registers_int(calloption : tproccalloption):tcpuregisterset;
+ begin
+@@ -75,47 +87,91 @@ unit cpupara;
+ end;
+
+
+- procedure taarch64paramanager.getintparaloc(pd : tabstractprocdef; nr : longint; var cgpara : tcgpara);
++ function is_hfa_internal(p: tdef; var basedef: tdef; var elecount: longint): boolean;
+ var
+- paraloc : pcgparalocation;
+- def : tdef;
++ i: longint;
++ sym: tsym;
++ tmpelecount: longint;
+ begin
+- if nr<1 then
+- internalerror(2002070801);
+- def:=tparavarsym(pd.paras[nr-1]).vardef;
+- cgpara.reset;
+- cgpara.size:=def_cgsize(def);
+- cgpara.intsize:=tcgsize2size[cgpara.size];
+- cgpara.alignment:=std_param_align;
+- cgpara.def:=def;
+- paraloc:=cgpara.add_location;
+- with paraloc^ do
+- begin
+- size:=OS_INT;
+- { the four first parameters are passed into registers }
+- if nr<=8 then
+- begin
+- loc:=LOC_REGISTER;
+- register:=newreg(R_INTREGISTER,RS_X0+nr-1,R_SUBWHOLE);
+- end
+- else
+- begin
+- { the other parameters are passed on the stack }
+- loc:=LOC_REFERENCE;
+- reference.index:=NR_STACK_POINTER_REG;
+- reference.offset:=(nr-9)*8;
+- end;
+- end;
++ result:=false;
++ case p.typ of
++ arraydef:
++ begin
++ if is_special_array(p) then
++ exit;
++ case tarraydef(p).elementdef.typ of
++ floatdef:
++ begin
++ { an array of empty records has no influence }
++ if tarraydef(p).elementdef.size=0 then
++ begin
++ result:=true;
++ exit
++ end;
++ tmpelecount:=0;
++ if not is_hfa_internal(tarraydef(p).elementdef,basedef,tmpelecount) then
++ exit;
++ { tmpelecount now contains the number of hfa elements in a
++ single array element (e.g. 2 if it's an array of a record
++ containing two singles) -> 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;
++ { 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;
+
+
+- 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;
+- 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;
++ { hidden function result parameter is passed in X8 (doesn't have to
++ be valid on return) according to the ABI
+
+- 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
+- begin
+- paradef:=getpointerdef(paradef);
+- loc:=LOC_REGISTER;
+- paracgsize := OS_ADDR;
+- paralen := tcgsize2size[OS_ADDR];
+- end
+- else
++ -- 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
+- 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;
+- begin
+- init_values(curintreg,curfloatreg,curmmreg,cur_stack_offset,sparesinglereg);
+-
+- 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)
++ function taarch64paramanager.create_varargs_paraloc_info(p: tabstractprocdef; varargspara: tvarargsparalist):longint;
++ begin
++ init_para_alloc_values;
++
++ { 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;
+Index: fpc/fpcsrc/compiler/aarch64/cpupi.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/cputarg.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/hlcgcpu.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpuadd.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpucnv.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpuinl.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpumat.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpumem.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ncpuset.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/ra64con.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64con.inc
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/aarch64/ra64dwa.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64dwa.inc
++++ fpc/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
+Index: fpc/fpcsrc/compiler/aarch64/ra64nor.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64nor.inc
++++ fpc/fpcsrc/compiler/aarch64/ra64nor.inc
+@@ -1,2 +1,2 @@
+ { don't edit, this file is generated from a64reg.dat }
+-226
++231
+Index: fpc/fpcsrc/compiler/aarch64/ra64num.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64num.inc
++++ fpc/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)
+Index: fpc/fpcsrc/compiler/aarch64/ra64rni.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64rni.inc
++++ fpc/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
+Index: fpc/fpcsrc/compiler/aarch64/ra64sri.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64sri.inc
++++ fpc/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,
+Index: fpc/fpcsrc/compiler/aarch64/ra64sta.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64sta.inc
++++ fpc/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
+Index: fpc/fpcsrc/compiler/aarch64/ra64std.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64std.inc
++++ fpc/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'
+Index: fpc/fpcsrc/compiler/aarch64/ra64sup.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aarch64/ra64sup.inc
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/aarch64/racpu.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/racpugas.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aarch64/rgcpu.pas
+===================================================================
+--- /dev/null
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/aasmtai.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aasmtai.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/aggas.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aggas.pas
++++ fpc/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^);
+Index: fpc/fpcsrc/compiler/aoptobj.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/aoptobj.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/arm/aasmcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/aasmcpu.pas
++++ fpc/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;
+@@ -1605,6 +1812,12 @@ implementation
+ 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
+ s:=s+'reg';
+@@ -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+1<opercnt) and (oper[op+1]^.typ=top_shifterop) then
++ with oper[op+1]^.shifterop^ do
++ 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);
++ 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;
+
++ function MakeRegList(reglist: tcpuregisterset): word;
++ var
++ i, w: word;
++ begin
++ result:=0;
++ w:=1;
++ for i:=RS_R0 to RS_R15 do
++ begin
++ if i in reglist then
++ result:=result or w;
++ w:=w shl 1
++ end;
++ end;
++
++ function getcoproc(reg: tregister): byte;
++ begin
++ if reg=NR_p15 then
++ result:=15
++ else
++ begin
++ Message1(asmw_e_invalid_opcode_and_operands,'Invalid coprocessor port');
++ result:=0;
++ end;
++ end;
++
++ function getcoprocreg(reg: tregister): byte;
++ begin
++ result:=getsupreg(reg)-getsupreg(NR_CR0);
++ end;
++
++ 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;
++
++ 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;
++
++ 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 is_sat then
++ begin
++ bytes:=bytes or ((typ and 1) shl 5);
++ bytes:=bytes or ((typ shr 1) shl 21);
++ end
++ else
++ 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;
++
+ begin
+ bytes:=$0;
++ bytelen:=4;
+ i_field:=0;
+ { evaluate and set condition code }
++ bytes:=bytes or (CondVal[condition] shl 28);
+
+ { condition code allowed? }
+
+ { setup rest of the instruction }
+ case insentry^.code[0] of
+- #$08:
++ #$01: // B/BL
+ begin
+ { set instruction code }
+- bytes:=bytes or (ord(insentry^.code[1]) shl 26);
+- bytes:=bytes or (ord(insentry^.code[2]) shl 21);
++ 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 }
++ { 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;
+
+- { set s if necessary }
++ 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;
+- #$ff:
+- internalerror(2005091101);
+- else
+- internalerror(2005091102);
+- end;
+- { we're finished, write code }
+- objdata.writebytes(bytes,sizeof(bytes));
+- 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]);
+
+-{$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;
+- }
++ if ops=3 then
++ begin
++ msb:=(oper[1]^.val+oper[2]^.val-1);
+
+- // 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
+- }
++ { 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);
+
+- 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 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;
+
+- if (data >= 0x1000)
+- {
+- errfunc (ERR_NONFATAL, "too long offset");
+- }
++ 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);
+
+- 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;
++ bytes:=bytes or (((Rd and $1E) shr 1) shl 16);
++ bytes:=bytes or ((Rd and $1) shl 7);
+
+- 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:=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);
+
+- 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,<shift>Rs
+- case 6: // AND Rd,Rn,Rm,<shift>imm
+- case 7: // AND Rd,Rn,<shift>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]
+- }
+- // <shift>
+- c |= shiftval (&ins->oprs[3]) << 5;
++ bytes:=bytes or (((Rd and $1E) shr 1) shl 12);
++ bytes:=bytes or ((Rd and $1) shl 22);
+
+- bytes[3] |= c;
+- }
++ 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);
+
+- // 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;
+- }
++ Rd:=getmmreg(oper[0]^.reg);
++ Rm:=getmmreg(oper[1]^.reg);
+
+- out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
+- return;
++ bytes:=bytes or (1 shl 8);
+
+- case 8: // MOV Rd,Rm
+- case 9: // MOV Rd,Rm,<shift>Rs
+- case 0xA: // MOV Rd,Rm,<shift>imm
+- case 0xB: // MOV Rd,<shift>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);
+- }
++ bytes:=bytes or ((Rd and $F) shl 12);
++ bytes:=bytes or (((Rd and $10) shr 4) shl 22);
+
+- // 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]
+- }
+- // <shift>
+- c |= shiftval (&ins->oprs[2]) << 5;
++ 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;
+
+- bytes[3] |= c;
+- }
++ bytes:=bytes or (Rn shl 16);
+
+- // 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;
+- }
++ 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;
+
+- out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
+- return;
++ bytes:=bytes or (Rn shl 16);
+
++ 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;
+
+- case 0xC: // CMP Rn,Rm
+- case 0xD: // CMP Rn,Rm,<shift>Rs
+- case 0xE: // CMP Rn,Rm,<shift>imm
+- case 0xF: // CMP Rn,<shift>imm
+- ++codes;
++ 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;
+
+- bytes[0] = c | *codes++;
++ bytes:=bytes or (1 shl 8);
++ end;
+
+- bytes[1] = *codes;
++ bytes:=bytes or (Rd shl 12);
++ bytes:=bytes or (Rn shl 16);
++ bytes:=bytes or (Rm shl 0);
++
++ 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);
+
+- // Implicit S code
+- bytes[1] |= 0x10;
++ if (ops=2) and
++ (oppostfix in [PF_F32F64,PF_F64F32]) then
++ begin
++ if oppostfix=PF_F32F64 then
++ begin
++ bytes:=bytes or (1 shl 8);
+
+- c = regval (&ins->oprs[0],1);
+- // Rn in low nibble
+- bytes[1] |= c;
++ 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;
+
+- // No destination
+- bytes[2] = 0;
++ bytes:=bytes and $FFF0FFFF;
++ bytes:=bytes or ($7 shl 16);
+
+- 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]
+- }
+- // <shift>
+- c |= shiftval (&ins->oprs[2]) << 5;
++ 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[3] |= c;
+- }
++ d:=rd and 1;
++ rd:=rd shr 1;
++ end;
++ R_SUBFD:
++ begin
++ rd:=getmmreg(oper[0]^.reg);
+
+- // 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;
+- }
++ d:=(rd shr 4) and 1;
++ rd:=rd and $F;
++ end;
++ end;
+
+- out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
+- return;
++ m:=0;
++ case getsubreg(oper[1]^.reg) of
++ R_SUBNONE:
++ rm:=getsupreg(oper[1]^.reg);
++ R_SUBFS:
++ begin
++ rm:=getmmreg(oper[1]^.reg);
+
+- case 0x10: // MRS Rd,<psr>
+- ++codes;
++ m:=rm and 1;
++ rm:=rm shr 1;
++ end;
++ R_SUBFD:
++ begin
++ rm:=getmmreg(oper[1]^.reg);
+
+- bytes[0] = c | *codes++;
++ m:=(rm shr 4) and 1;
++ rm:=rm and $F;
++ 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 if ops=2 then
++ begin
++ case oppostfix of
++ PF_S32F64,
++ PF_U32F64,
++ PF_F64S32,
++ PF_F64U32:
++ bytes:=bytes or (1 shl 8);
++ end;
+
+- bytes[2] = c << 4;
++ 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;
+
+- bytes[3] = 0;
++ bytes:=bytes or (1 shl 18);
+
+- c = ins->oprs[1].basereg;
++ D:=rd and $1; Rd:=Rd shr 1;
+
+- if (c == R_CPSR || c == R_SPSR)
+- {
+- if (c == R_SPSR)
+- {
+- bytes[1] |= 0x40;
+- }
+- }
+- else
+- {
+- errfunc (ERR_NONFATAL, "CPSR or SPSR expected");
+- }
++ 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;
+
+- out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
++ M:=rm and $1; Rm:=Rm shr 1;
+
+- return;
++ 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;
+
+- case 0x11: // MSR <psr>,Rm
+- case 0x12: // MSR <psrf>,Rm
+- case 0x13: // MSR <psrf>,#expression
+- ++codes;
++ bytes:=bytes or (Rd shl 12);
++ bytes:=bytes or (Rm shl 0);
+
+- bytes[0] = c | *codes++;
++ 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);
+
+- bytes[1] = *codes++;
++ 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] = *codes;
++ 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');
+
++ rn:=16;
++ end;
++ else
++ Rn:=0;
++ message(asmw_e_invalid_opcode_and_operands);
++ end;
+
+- if (keep == 0x11 || keep == 0x12)
+- {
+- // Rm
+- c = regval (&ins->oprs[1],1);
++ 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;
+
+- bytes[3] = c;
+- }
+- else
+- {
+- int shimm;
++ 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;
+
+- shimm = imm_shift (ins->oprs[1].offset);
++ 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);
+
+- if (shimm == -1)
+- {
+- errfunc (ERR_NONFATAL, "cannot create that constant");
+- }
+- bytes[3] = shimm & 0xFF;
+- bytes[2] |= (shimm & 0xF00) >> 8;
+- }
++ bytes:=bytes or (Rd shl 12);
++ bytes:=bytes or (D shl 22);
+
+- c = ins->oprs[0].basereg;
++ rn:=rn-oper[2]^.val;
+
+- 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;
++ 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);
+
+- case 0x14: // MUL Rd,Rm,Rs
+- case 0x15: // MULA Rd,Rm,Rs,Rn
+- ++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[0] = c | *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[1] = *codes++;
++ bytes:=bytes or (Rn shl 16);
+
+- bytes[3] = *codes;
++ { 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;
+
+- // Rd
+- bytes[1] |= regval (&ins->oprs[0],1);
+- if (has_S_code)
+- bytes[1] |= 0x10;
++ 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;
+
+- // Rm
+- bytes[3] |= regval (&ins->oprs[1],1);
++ dp_operation:=(oper[1]^.subreg=R_SUBFD);
++ if oper[1]^.regset^=[] then
++ message1(asmw_e_invalid_opcode_and_operands, 'Regset cannot be empty');
++
++ rd:=0;
++ for r:=0 to 31 do
++ if r in oper[1]^.regset^ then
++ begin
++ rd:=r;
++ break;
++ end;
+
+- // Rs
+- bytes[2] = regval (&ins->oprs[2],1);
++ rn:=32-rd;
++ for r:=rd+1 to 31 do
++ if not(r in oper[1]^.regset^) then
++ begin
++ rn:=r-rd;
++ break;
++ end;
+
+- if (keep == 0x15)
+- {
+- bytes[2] |= regval (&ins->oprs[3],1) << 4;
+- }
+- break;
++ if dp_operation then
++ begin
++ bytes:=bytes or (1 shl 8);
+
+- case 0x16: // SMLAL RdHi,RdLo,Rm,Rs
+- ++codes;
++ bytes:=bytes or (rn*2);
+
+- bytes[0] = c | *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[1] = *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:=0;
++ for r:=0 to 31 do
++ if r in oper[0]^.regset^ then
++ begin
++ rd:=r;
++ break;
++ end;
+
+- bytes[3] = *codes;
++ rn:=32-rd;
++ for r:=rd+1 to 31 do
++ if not(r in oper[0]^.regset^) then
++ begin
++ rn:=r-rd;
++ break;
++ end;
+
+- // RdHi
+- bytes[1] |= regval (&ins->oprs[1],1);
+- if (has_S_code)
+- bytes[1] |= 0x10;
++ if dp_operation then
++ begin
++ bytes:=bytes or (1 shl 8);
+
+- // RdLo
+- bytes[2] = regval (&ins->oprs[0],1) << 4;
+- // Rm
+- bytes[3] |= regval (&ins->oprs[2],1);
++ bytes:=bytes or (rn*2);
+
+- // Rs
+- bytes[2] |= regval (&ins->oprs[3],1);
++ 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;
+
+- break;
++ 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);
+
+- case 0x17: // LDR Rd, expression
+- ++codes;
++ if getsubreg(oper[0]^.reg)=R_SUBFD then
++ begin
++ bytes:=bytes or (1 shl 8);
+
+- bytes[0] = c | *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;
+
+- bytes[1] = *codes++;
++ { 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;
+
+- // 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");
+- }
++ offset:=offset div 4;
+
+- // Rn - implicit R15
+- bytes[1] |= 0xF;
++ 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;
+
+- if (ins->oprs[1].segment != segment)
+- {
+- errfunc (ERR_NONFATAL, "label not in same segment");
+- }
++ 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;
+
+- data = ins->oprs[1].offset - (offset + 8);
++ { 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;
+
+- if (data < 0)
+- {
+- data = -data;
+- }
+- else
+- {
+- bytes[1] |= 0x80;
+- }
++ { 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;
+
+- if (data >= 0x1000)
+- {
+- errfunc (ERR_NONFATAL, "too long offset");
+- }
++ 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[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
+- }
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
++ bytes:=bytes or ord(insentry^.code[2]);
+
+- if (has_W_code)
+- {
+- bytes[1] |= 0x20; // write-back
+- }
++ if insentry^.code[0]=#$63 then
++ bytes:=bytes or (CondVal[condition] shl 8);
+
+- // Rn
+- c = regval (&ins->oprs[1],1);
+- bytes[1] |= c;
++ 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 (c == 0x15) // R15
+- data = -8;
+- else
+- data = 0;
++ 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;
+
+- if (data < 0)
+- {
+- data = -data;
+- }
+- else
+- {
+- bytes[1] |= 0x80;
+- }
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
++ bytes:=bytes or ord(insentry^.code[2]);
+
+- 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");
+- }
++ 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;
+
+- 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;
+- }
+- }
++ { 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;
+
+- break;
++ { 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;
+
+- case 0x22: // LDRH Rd, expression
+- ++codes;
++ { 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;
+
+- bytes[0] = c | 0x01; // Implicit pre-index
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
++ { set opers }
++ bytes:=bytes or (getsupreg(oper[0]^.reg) and $7);
+
+- bytes[1] = *codes++;
++ 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;
+
+- // Rd
+- bytes[2] = regval (&ins->oprs[0],1) << 4;
++ offset:=offset div 2;
++ end
++ else
++ offset:=oper[1]^.val div 2;
+
+- // Rn - implicit R15
+- bytes[1] |= 0xF;
++ 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;
+
+- if (ins->oprs[1].segment != segment)
+- {
+- errfunc (ERR_NONFATAL, "label not in same segment");
+- }
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
+
+- data = ins->oprs[1].offset - (offset + 8);
++ 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);
+
+- if (data < 0)
+- {
+- data = -data;
+- }
+- else
+- {
+- bytes[1] |= 0x80;
+- }
++ 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);
+
+- if (data >= 0x100)
+- {
+- errfunc (ERR_NONFATAL, "too long offset");
+- }
+- bytes[3] = *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;
++ end;
++ end;
++ #$6A: { Thumb: IT }
++ begin
++ bytelen:=2;
++ bytes:=0;
+
+- bytes[2] |= ((data & 0xF0) >> 4);
+- bytes[3] |= data & 0xF;
+- break;
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
++ bytes:=bytes or (ord(insentry^.code[2]) shl 0);
+
+- case 0x23: // LDRH Rd, Rn
+- ++codes;
++ bytes:=bytes or (CondVal[oper[0]^.cc] shl 4);
+
+- bytes[0] = c | 0x01; // Implicit pre-index
++ 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;
+
+- bytes[1] = *codes++;
++ 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;
+
+- // Rd
+- bytes[2] = regval (&ins->oprs[0],1) << 4;
++ { 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;
+
+- // Rn
+- c = regval (&ins->oprs[1],1);
+- bytes[1] |= c;
++ { set opcode }
++ bytes:=bytes or (ord(insentry^.code[1]) shl 8);
++ bytes:=bytes or ord(insentry^.code[2]);
++
++ 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 (c == 0x15) // R15
+- data = -8;
+- else
+- data = 0;
++ 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 (data < 0)
+- {
+- data = -data;
+- }
+- else
+- {
+- bytes[1] |= 0x80;
+- }
++ 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 (data >= 0x100)
+- {
+- errfunc (ERR_NONFATAL, "too long offset");
+- }
+- bytes[3] = *codes++;
++ 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);
+
+- 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");
+- }
+- }
++ 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);
+
+- bytes[3] = *codes++;
++ 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 (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");
+- }
++ 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 & 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;
++ 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 0x26: // LDM/STM Rn, {reg-list}
+- ++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;
++ offset:=offset;
++ end;
+
+- bytes[0] |= ( *codes >> 4) & 0xF;
+- bytes[1] = ( *codes << 4) & 0xF0;
+- ++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;
+
+- if (has_W_code)
+- {
+- bytes[1] |= 0x20;
+- }
+- if (has_F_code)
+- {
+- bytes[1] |= 0x40;
+- }
++ 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
+- bytes[1] |= regval (&ins->oprs[0],1);
++ 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;
+
+- data = ins->oprs[1].basereg;
++ 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);
++
++ if (ops>=(offset+2)) and
++ (oper[offset+1]^.typ=top_const) then
++ bytes:=bytes or (oper[offset+1]^.val and $1F);
+
+- bytes[2] = ((data >> 8) & 0xFF);
+- bytes[3] = (data & 0xFF);
++ 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]);
+
+- break;
++ 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;
+
+- case 0x27: // SWP Rd, Rm, [Rn]
+- ++codes;
++ 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;
+
+- bytes[0] = c;
++ 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] |= *codes++;
++ bytes:=bytes or (i_field and $1F);
++ 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;
+-
+- 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
+- {
++ 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]);
++
++ 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);
+
+- }
+- ++codes;
+- }
+- out (offset, segment, bytes, OUT_RAWDATA+4, NO_SEG, NO_SEG);
+-}
++ 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]);
+
+-*)
+-{$endif dummy}
++ 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;
+
+- constructor tai_thumb_func.create;
+- begin
+- inherited create;
+- typ:=ait_thumb_func;
+- end;
++ 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 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);
++
++ 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);
++
++ 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;
++
++ 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);
++
++ 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;
++
++ for r:=0 to 15 do
++ if r in oper[1]^.regset^ then
++ bytes:=bytes or (1 shl r);
++
++ 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;
++
++ 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);
++
++ 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 (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 (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 opcode=A_MRS then
++ begin
++ bytes:=bytes or (getsupreg(oper[0]^.reg) shl 8);
++
++ case oper[1]^.reg of
++ NR_MSP: bytes:=bytes or $08;
++ NR_PSP: bytes:=bytes or $09;
++
++ NR_IPSR: bytes:=bytes or $05;
++ NR_EPSR: bytes:=bytes or $06;
++ NR_APSR: bytes:=bytes or $00;
++
++ 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);
++
++ 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;
++
++ NR_MSP: bytes:=bytes or $08;
++ NR_PSP: bytes:=bytes or $09;
++
++ 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;
++ 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]);
++
++ 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;
++
++ 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;
++
++ 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);
++
++ 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:=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;
++
++ 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;
++
++ 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);
++
++ case opcode of
++ A_FLT:
++ begin
++ bytes:=bytes or (getsupreg(oper[0]^.reg) shl 16);
++ bytes:=bytes or (getsupreg(oper[1]^.reg) shl 12);
++
++ 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;
++
++ 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);
++
++ 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);
++
++ 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;
++
++ { 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);
++
++ { we're finished, write code }
++ objdata.writebytes(bytes,bytelen);
++ end;
+
+ begin
+ cai_align:=tai_align;
+Index: fpc/fpcsrc/compiler/arm/agarmgas.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/agarmgas.pas
++++ fpc/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:
+Index: fpc/fpcsrc/compiler/arm/aoptcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/aoptcpu.pas
++++ fpc/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,
+Index: fpc/fpcsrc/compiler/arm/armatt.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armatt.inc
++++ fpc/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'
+ );
+Index: fpc/fpcsrc/compiler/arm/armatts.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armatts.inc
++++ fpc/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
+ );
+Index: fpc/fpcsrc/compiler/arm/armins.dat
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armins.dat
++++ fpc/fpcsrc/compiler/arm/armins.dat
+@@ -85,713 +85,1756 @@
+ [NONE]
+ void void none
+
+-[ABScc]
+-
+-[ACScc]
++[ADCcc]
++reglo,reglo \x6B\x41\x40 THUMB,ARMv4T
+
+-[ASNcc]
++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
++
++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
++
++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
+
+-[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
++[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
+
+-[CDP]
+-reg8,reg8 \300\1\x10\101 ARM7
++reg32 \3\x01\x2F\xFF\x10 ARM32,ARMv4T
+
+-[CMFcc]
+-
+-[CMFEcc]
++[CDP]
++reg8,reg8 \300\1\x10\101 ARM32,ARMv4
+
+ [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
++reglo,reglo \x6B\x42\xC0 THUMB,ARMv4T
++
++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
++
++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
++
++reg32,reg32 \xC\x1\x40 ARM32,ARMv4
++reg32,reg32,shifterop \xE\x1\x40 ARM32,ARMv4
++reg32,immshifter \xF\x3\x40 ARM32,ARMv4
+
+-[COScc]
++[CMFcc]
++fpureg,fpureg \xA2\xE\x90 ARM32,FPA
++fpureg,immshifter \xA2\xE\x90 ARM32,FPA
+
+-[CPS]
+-[CPSID]
+-[CPSIE]
++[CMFEcc]
++fpureg,fpureg \xA2\xE\xC0 ARM32,FPA
++fpureg,immshifter \xA2\xE\xC0 ARM32,FPA
+
+-[DVFcc]
++[STFcc]
++fpureg,memam2 \xA0\xC\x00\x1\x0 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
++[LDFcc]
++fpureg,memam2 \xA0\xC\x10\x1\x0 ARM32,FPA
+
+-[EXPcc]
++[LFMcc]
++fpureg,imm32,memam2 \xA0\xC\x10\x2\x0 ARM32,FPA
++fpureg,immshifter,memam2 \xA0\xC\x10\x2\x0 ARM32,FPA
+
+-[FDVcc]
++[CLZcc]
++reg32,reg32 \x80\xFA\xB0\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32 \x32\x01\x6F\xF\x10 ARM32,ARMv4
+
+-[FLTcc]
++[CPS]
++immshifter \x8F\xF3\xAF\x81\x00 THUMB32,ARMv6T2
++immshifter \x46\xF1\x2\x0\x0 ARM32,ARMv6
+
+-[FIXcc]
++[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
+
+-[FMLcc]
++[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
+
+-[FRDcc]
++[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
++
++[MCR2cc]
++regf,immshifter,reg32,regf,regf \x1C\xFE\x0\x1 ARM32,ARMv5T
++regf,immshifter,reg32,regf,regf,immshifter \x1C\xFE\x0\x1 ARM32,ARMv5T
++
++[MRCcc]
++regf,immshifter,reg32,regf,regf \x1C\xE\x10\x1 ARM32,ARMv4
++regf,immshifter,reg32,regf,regf,immshifter \x1C\xE\x10\x1 ARM32,ARMv4
++
++[MRC2cc]
++regf,immshifter,reg32,regf,regf \x1C\xFE\x10\x1 ARM32,ARMv5T
++regf,immshifter,reg32,regf,regf,immshifter \x1C\xFE\x10\x1 ARM32,ARMv5T
+
+-[LFMcc]
+-reg32,imm8,fpureg \xF0\x02\x01 FPA
++[MCRRcc]
++regf,immshifter,reg32,reg32,regf \x1D\xC\x40\x0 ARM32,ARMv5TE
+
+-[LGNcc]
++[MCRR2cc]
++regf,immshifter,reg32,reg32,regf \x1D\xFC\x40\x0 ARM32,ARMv6
+
+-[LOGcc]
++[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
+-
+-[NOP]
+-
+-[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
++reglo,reglo \x6B\x43\xc0 THUMB,ARMv4T
+
+-[RDFcc]
++reg32,immshifter \x80\xF0\x6F\x0\x0 THUMB32,ARMv6T2
++reg32,reg32 \x80\xEA\x6F\x0\x0 THUMB32,WIDE,ARMv6T2
+
+-[RFScc]
++reg32,reg32 \x8\x1\xE0 ARM32,ARMv4
++reg32,reg32,shifterop \xA\x1\xE0 ARM32,ARMv4
++reg32,immshifter \xB\x1\xE0 ARM32,ARMv4
++
++[VMOVcc]
++vreg,vreg \x90\xEE\xB0\xA\x40 THUMB32,VFPv2
++vreg,vreg \x40\xE\xB0\xA\x40 ARM32,VFPv2
++
++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
++
++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
++
++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
+
+-[RFCcc]
++[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
+
+-[RMFcc]
++[ORRcc]
++reglo,reglo \x6B\x43\x00 THUMB,ARMv4T
+
+-[RPWcc]
++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
++
++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
+
+ [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
+-
+-[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
++reglo,reglo,immzero \x6B\x42\x40 THUMB,ARMv4T
+
+-[RSFcc]
++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
+
+-[RNDcc]
+-
+-[POLcc]
++[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]
+-
+-[FABSScc]
+-
+-[FADDDcc]
+-
+-[FADDScc]
+-
+-[FCMPDcc]
+-
+-[FCMPEDcc]
+-
+-[FCMPEScc]
+-
+-[FCMPEZDcc]
+-
+-[FCMPEZScc]
+-
+-[FCMPScc]
+-
+-[FCMPZDcc]
+-
+-[FCMPZScc]
+-
+-[FCPYDcc]
+-
+-[FCPYScc]
+-
+-[FCVTDScc]
+-
+-[FCVTSDcc]
+-
+-[FDIVDcc]
+-
+-[FDIVScc]
+-
+-[FLDDcc]
+-
+-[FLDMcc]
+-
+-[FLDScc]
+-
+-[FMACDcc]
+-
+-[FMACScc]
+-
+-[FMDHRcc]
+-
+-[FMDLRcc]
+-
+-[FMRDHcc]
+-
+-[FMRDLcc]
+-
+-[FMRScc]
+-
+-[FMRXcc]
+-
+-[FMSCDcc]
+-
+-[FMSCScc]
+-
+-[FMSRcc]
+-
+-[FMSTATcc]
+-
+-[FMULDcc]
+-
+-[FMULScc]
+-
+-[FMXRcc]
+-
+-[FNEGDcc]
+-
+-[FNEGScc]
+-
+-[FNMACDcc]
+-
+-[FNMACScc]
+-
+-[FNMSCDcc]
+-
+-[FNMSCScc]
+-
+-[FNMULDcc]
+-
+-[FNMULScc]
+-
+-[FSITODcc]
+-
+-[FSITOScc]
+-
+-[FSQRTDcc]
+-
+-[FSQRTScc]
++[LDRHTcc]
++reg32,memam2 \x88\xF8\x30\xE\x0\0 THUMB32,ARMv6T2
++reg32,memam2 \x19\x0\x30\x0\xB0 ARM32,ARMv4
++
++[STRHTcc]
++reg32,memam2 \x88\xF8\x20\xE\x0\0 THUMB32,ARMv6T2
++
++reg32,memam2 \x88\xF8\x20\xE\x0\0 THUMB32,ARMv6T2
++reg32,memam2 \x1E\x0\x20\x0\xB0 ARM32,ARMv4
++
++[LDRSBTcc]
++reg32,memam2 \x88\xF9\x10\xE\x0\0 THUMB32,ARMv6T2
++reg32,memam2 \x1E\x0\x30\x0\xD0 ARM32,ARMv4
++
++[LDRSHTcc]
++reg32,memam2 \x88\xF9\x30\xE\x0\0 THUMB32,ARMv6T2
++reg32,memam2 \x1E\x0\x30\x0\xF0 ARM32,ARMv4
+
+ [FSTDcc]
++vreg,memam2 \x95\xED\x0\xA THUMB32,VFPv2
++vreg,memam2 \x45\xD\x0\xA ARM32,VFPv2
+
+ [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
+
+ [FSTScc]
++vreg,memam2 \x95\xED\x0\xA THUMB32,VFPv2
++vreg,memam2 \x45\xD\x0\xA ARM32,VFPv2
+
+-[FSUBDcc]
+-
+-[FSUBScc]
++; ARMv6
+
+-[FTOSIDcc]
++[BFCcc]
++reg32,immshifter,immshifter \x84\xF3\x6F\x0\x0 THUMB32,ARMv6T2
++reg32,immshifter,imm32 \x84\xF3\x6F\x0\x0 THUMB32,ARMv6T2
+
+-[FTOSIScc]
++reg32,immshifter,immshifter \x2D\x7\xC0\x0\x1F ARM32,ARMv4
++reg32,immshifter,imm32 \x2D\x7\xC0\x0\x1F ARM32,ARMv4
+
+-[FTOUIDcc]
++[BFIcc]
++reg32,reg32,immshifter,immshifter \x84\xF3\x60\x0\x0 THUMB32,ARMv6T2
++reg32,reg32,immshifter,imm32 \x84\xF3\x60\x0\x0 THUMB32,ARMv6T2
+
+-[FTOUIScc]
++reg32,reg32,immshifter,immshifter \x2D\x7\xC0\x0\x10 ARM32,ARMv4
++reg32,reg32,immshifter,imm32 \x2D\x7\xC0\x0\x10 ARM32,ARMv4
+
+-[FUITODcc]
++[CLREX]
++void \x80\xF3\xBF\x8F\x2F THUMB32,ARMv7
++void \x2F\xF5\x7F\xF0\x1F ARM32,ARMv6K
+
+-[FUITOScc]
++[LDREXcc]
++reg32,memam6 \x8A\xE8\x50\x0F\x00 THUMB32,ARMv6T2
++reg32,memam6 \x18\x01\x90\x0F\x9F ARM32,ARMv4
+
+-[FMDRRcc]
++[LDREXBcc]
++reg32,memam6 \x8A\xE8\xD0\x0F\x4F THUMB32,ARMv7
++reg32,memam6 \x18\x01\xD0\x0F\x9F ARM32,ARMv4
+
+-[FMRRDcc]
++[LDREXDcc]
++reg32,reg32,memam6 \x8A\xE8\xD0\x00\x7F THUMB32,ARMv7
++reg32,reg32,memam6 \x18\x01\xB0\x0F\x9F ARM32,ARMv4
+
+-; ARMv6
++[LDREXHcc]
++reg32,memam6 \x8A\xE8\xD0\x0F\x5F THUMB32,ARMv7
++reg32,memam6 \x18\x01\xF0\x0F\x9F ARM32,ARMv4
+
+-[BFCcc]
++[STREXcc]
++reg32,reg32,memam6 \x8B\xE8\x40\x00\x00 THUMB32,ARMv6T2
++reg32,reg32,memam6 \x18\x01\x80\x0F\x90 ARM32,ARMv4
+
+-[BFIcc]
++[STREXBcc]
++reg32,reg32,memam6 \x8B\xE8\xC0\x0F\x40 THUMB32,ARMv7
++reg32,reg32,memam6 \x18\x01\xC0\x0F\x90 ARM32,ARMv4
+
+-[CLREX]
++[STREXDcc]
++reg32,reg32,reg32,memam6 \x8B\xE8\xC0\x00\x70 THUMB32,ARMv7
++reg32,reg32,reg32,memam6 \x18\x01\xA0\x0F\x90 ARM32,ARMv4
+
+-[LDREXcc]
+-[LDREXBcc]
+-[LDREXDcc]
+-[LDREXHcc]
++[STREXHcc]
++reg32,reg32,memam6 \x8B\xE8\xC0\x0F\x50 THUMB32,ARMv7
++reg32,reg32,memam6 \x18\x01\xE0\x0F\x90 ARM32,ARMv4
+
+ [MLScc]
++reg32,reg32,reg32,reg32 \x80\xFB\x0\x0\x10 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x15\x00\x60\x9 ARM32,ARMv6T2
++
++[PKHBTcc]
++reg32,reg32,reg32 \x80\xEA\xC0\x0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x80\xEA\xC0\x0\x0 THUMB32,ARMv6T2
++
++reg32,reg32,reg32 \x16\x6\x80\x1 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x6\x80\x1 ARM32,ARMv6
++
++[PKHTBcc]
++reg32,reg32,reg32 \x80\xEA\xC0\x0\x10 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x80\xEA\xC0\x0\x10 THUMB32,ARMv6T2
+
+-[PKHcc]
++reg32,reg32,reg32 \x16\x6\x80\x1 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x6\x80\x5 ARM32,ARMv6
+
+ [PLI]
++memam2 \x87\xF9\x10\xF0\x0 THUMB32,ARMv7
++memam2 \x25\xF4\x50\xF0\x0 ARM32,ARMv7
+
+ [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
+
+ [RBITcc]
++reg32,reg32 \x80\xFA\x90\xF0\xA0 THUMB32,ARMv6T2
++reg32,reg32 \x32\x6\xFF\xF\x30 ARM32,ARMv6T2
+
+ [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
++
+ [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
++
+ [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
+
+ [SADD16cc]
++reg32,reg32,reg32 \x80\xFA\90\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xF1 ARM32,ARMv6
++
+ [SADD8cc]
++reg32,reg32,reg32 \x80\xFA\80\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xF9 ARM32,ARMv6
++
+ [SASXcc]
++reg32,reg32,reg32 \x80\xFA\A0\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xF3 ARM32,ARMv6
+
+ [SBFXcc]
++reg32,reg32,immshifter,immshifter \x84\xF3\x40\x0\x0 THUMB32,ARMv6T2
++reg32,reg32,immshifter,immshifter \x2D\x7\xA0\x0\x50 ARM32,ARMv6T2
+
+ [SELcc]
++reg32,reg32,reg32 \x80\xFA\xA0\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x80\xFB ARM32,ARMv6
+
+ [SETEND]
++immshifter \x2B\xF1\x01\x0\x0 ARM32,ARMv6
+
+ [SEVcc]
++void \x64\xBF\x40 THUMB,ARMv7
++void \x2F\x3\x20\xF0\x4 ARM32,ARMv6K
+
+ [ASRcc]
++reglo,immshifter \x60\x1\x0 THUMB,ARMv4T
++reglo,reglo,immshifter \x60\x1\x0 THUMB,ARMv4T
++reglo,reglo \x6B\x41\x0 THUMB,ARMv4T
++
++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
++
++reg32,reg32,reg32 \x30\x1\xA0\x0\x50 ARM32,ARMv4
++reg32,reg32,immshifter \x30\x1\xA0\x0\x40 ARM32,ARMv4
+
+ [LSRcc]
++reglo,immshifter \x60\x8\x0 THUMB,ARMv4T
++reglo,reglo,immshifter \x60\x8\x0 THUMB,ARMv4T
++reglo,reglo \x6B\x40\xC0 THUMB,ARMv4T
++
++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
++
++reg32,reg32,reg32 \x30\x1\xA0\x0\x30 ARM32,ARMv4
++reg32,reg32,immshifter \x30\x1\xA0\x0\x20 ARM32,ARMv4
+
+ [LSLcc]
++reglo,immshifter \x60\x0\x0 THUMB,ARMv4T
++reglo,reglo,immshifter \x60\x0\x0 THUMB,ARMv4T
++reglo,reglo \x6B\x40\x80 THUMB,ARMv4T
++
++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
++
++reg32,reg32,reg32 \x30\x1\xA0\x0\x10 ARM32,ARMv4
++reg32,reg32,immshifter \x30\x1\xA0\x0\x00 ARM32,ARMv4
+
+ [RORcc]
++reglo,reglo \x6B\x41\xC0 THUMB,ARMv4T
++
++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
++
++reg32,reg32,reg32 \x30\x1\xA0\x0\x70 ARM32,ARMv4
++reg32,reg32,immshifter \x30\x1\xA0\x0\x60 ARM32,ARMv4
++
++[RRXcc]
++reg32,reg32 \x80\xEA\x4F\x00\x30 THUMB32,ARMv6T2
++reg32,reg32 \x30\x1\xA0\x0\x60 ARM32,ARMv4
++
++[UMAALcc]
++reg32,reg32,reg32,reg32 \x85\xFB\xE0\x0\x60 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x16\x0\x40\x9 ARM32,ARMv6
+
+ [SHADD16cc]
++reg32,reg32,reg32 \x80\xFA\x90\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xF1 ARM32,ARMv6
++
+ [SHADD8cc]
++reg32,reg32,reg32 \x80\xFA\x80\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xF9 ARM32,ARMv6
++
+ [SHASXcc]
++reg32,reg32,reg32 \x80\xFA\xA0\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xF3 ARM32,ARMv6
++
+ [SHSAXcc]
++reg32,reg32,reg32 \x80\xFA\xE0\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xF5 ARM32,ARMv6
++
+ [SHSUB16cc]
++reg32,reg32,reg32 \x80\xFA\xD0\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xF7 ARM32,ARMv6
++
+ [SHSUB8cc]
++reg32,reg32,reg32 \x80\xFA\xC0\xF0\x20 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x30\xFF ARM32,ARMv6
+
+ [SMLADcc]
++reg32,reg32,reg32,reg32 \x80\xFB\x20\x0\x00 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x15\x7\x00\x1 ARM32,ARMv6
++
+ [SMLALDcc]
++reg32,reg32,reg32,reg32 \x85\xFB\xC0\x0\xC0 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x16\x7\x40\x1 ARM32,ARMv4
++
+ [SMLSDcc]
++reg32,reg32,reg32,reg32 \x80\xFB\x40\x0\x00 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x15\x7\x00\x5 ARM32,ARMv6
++
+ [SMLSLDcc]
++reg32,reg32,reg32,reg32 \x85\xFB\xD0\x0\xC0 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x16\x7\x40\x5 ARM32,ARMv6
++
+ [SMMLAcc]
++reg32,reg32,reg32,reg32 \x80\xFB\x50\x0\x00 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x15\x7\x50\x1 ARM32,ARMv6
++
+ [SMMLScc]
++reg32,reg32,reg32,reg32 \x80\xFB\x60\x0\x00 THUMB32,ARMv6T2
++reg32,reg32,reg32,reg32 \x15\x7\x50\xD ARM32,ARMv6
++
+ [SMMULcc]
++reg32,reg32,reg32 \x80\xFB\x50\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x15\x7\x50\x1\xF ARM32,ARMv6
++
+ [SMUADcc]
++reg32,reg32,reg32 \x80\xFB\x20\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x15\x7\x00\x1\xF ARM32,ARMv6
++
+ [SMUSDcc]
++reg32,reg32,reg32 \x80\xFB\x40\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x15\x7\x00\x5\xF ARM32,ARMv6
+
+ [SRScc]
+
+ [SSATcc]
++reg32,immshifter,reg32 \x83\xF3\x00\x0\x0 THUMB32,ARMv6T2
++reg32,immshifter,reg32,shifterop \x83\xF3\x00\x0\x0 THUMB32,ARMv6T2
++
++reg32,immshifter,reg32 \x2A\x6\xA0\x0\x10 ARM32,ARMv6
++reg32,immshifter,reg32,shifterop \x2A\x6\xA0\x0\x10 ARM32,ARMv6
++
+ [SSAT16cc]
++reg32,immshifter,reg32 \x83\xF3\x20\x0\x0 THUMB32,ARMv6T2
++reg32,immshifter,reg32 \x2A\x6\xA0\xF\x30 ARM32,ARMv6
++
+ [SSAXcc]
++reg32,reg32,reg32 \x80\xFA\xE0\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xF5 ARM32,ARMv6
+
+ [SSUB16cc]
+-[SSUB8cc]
++reg32,reg32,reg32 \x80\xFA\xD0\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xF7 ARM32,ARMv6
+
+-[STREXcc]
+-[STREXBcc]
+-[STREXDcc]
+-[STREXHcc]
++[SSUB8cc]
++reg32,reg32,reg32 \x80\xFA\xC0\xF0\x0 THUMB32,ARMv6T2
++reg32,reg32,reg32 \x16\x06\x10\xFF ARM32,ARMv6
+
+ [SXTABcc]
++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\x06\xA0\x07 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x06\xA0\x07 ARM32,ARMv6
++
+ [SXTAB16cc]
++reg32,reg32,reg32 \x86\xFA\x20\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x86\xFA\x20\xF0\x80 THUMB32,ARMv6T2
++
++reg32,reg32,reg32 \x16\x06\x80\x07 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x06\x80\x07 ARM32,ARMv6
++
+ [SXTAHcc]
++reg32,reg32,reg32 \x86\xFA\x00\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x86\xFA\x00\xF0\x80 THUMB32,ARMv6T2
++
++reg32,reg32,reg32 \x16\x06\xB0\x07 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x06\xB0\x07 ARM32,ARMv6
++
++[UBFXcc]
++reg32,reg32,immshifter,immshifter \x84\xF3\xC0\x0\x0 THUMB32,ARMv6T2
++reg32,reg32,immshifter,immshifter \x2D\x7\xE0\x0\x50 ARM32,ARMv4
++
++[UXTABcc]
++reg32,reg32,reg32 \x86\xFA\x50\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x86\xFA\x50\xF0\x80 THUMB32,ARMv6T2
++
++reg32,reg32,reg32 \x16\x6\xE0\x7 ARM32,ARMv6
++reg32,reg32,reg32,shifterop \x16\x6\xE0\x7 ARM32,ARMv6
++
++[UXTAB16cc]
++reg32,reg32,reg32 \x86\xFA\x30\xF0\x80 THUMB32,ARMv6T2
++reg32,reg32,reg32,shifterop \x86\xFA\x30\xF0\x80 THUMB32,ARMv6T2
++
++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
++
+ [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
+
+-[TBB]
+-[TBH]
++[TBBcc]
++memam2 \x8E\xE8\xD0\xF0\x00 THUMB32,ARMv6T2
++
++[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
+Index: fpc/fpcsrc/compiler/arm/armnop.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armnop.inc
++++ fpc/fpcsrc/compiler/arm/armnop.inc
+@@ -1,2 +1,2 @@
+ { don't edit, this file is generated from armins.dat }
+-105;
++952;
+Index: fpc/fpcsrc/compiler/arm/armop.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armop.inc
++++ fpc/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
+ );
+Index: fpc/fpcsrc/compiler/arm/armreg.dat
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armreg.dat
++++ fpc/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
+Index: fpc/fpcsrc/compiler/arm/armtab.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/armtab.inc
++++ fpc/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_memory or ot_bits32,ot_none,ot_none,ot_none);
++ 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_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_memory or ot_bits32,ot_none,ot_none,ot_none);
++ 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_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_memory or ot_bits32,ot_none,ot_none,ot_none);
+- code : #15#15;
+- flags : if_arm7
++ 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_immediate24,ot_none,ot_none,ot_none);
+- code : #15#15;
+- flags : if_arm7
++ 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);
++ optypes : (ot_reg32,ot_none,ot_none,ot_none,ot_none,ot_none);
+ code : #3#1#47#255#16;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4t
+ ),
+ (
+ opcode : A_CDP;
+ ops : 2;
+- optypes : (ot_reg8,ot_reg8,ot_none,ot_none);
++ optypes : (ot_reg8,ot_reg8,ot_none,ot_none,ot_none,ot_none);
+ code : #192#1#16#65;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_CMN;
+ ops : 2;
+- optypes : (ot_reg32,ot_reg32,ot_none,ot_none);
+- code : #12#1#96;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #13#1#96;
+- flags : if_arm7
++ 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_immediate,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none);
+ code : #14#1#96;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_CMN;
+ ops : 2;
+- optypes : (ot_reg32,ot_immediate,ot_none,ot_none);
+- code : #15#3#96;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_none,ot_none);
+- code : #12#1#64;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #13#1#64;
+- flags : if_arm7
++ 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_immediate,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none);
+ code : #14#1#64;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_CMP;
+ ops : 2;
+- optypes : (ot_reg32,ot_immediate,ot_none,ot_none);
++ optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none);
+ code : #15#3#64;
+- flags : if_arm7
++ 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);
+- code : #39#1#1;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #4#0#32;
+- flags : if_arm7
++ 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_reg32);
+- code : #5#0#32;
+- flags : if_arm7
++ 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_immediate);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none);
+ code : #6#0#32;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_EOR;
+ 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#32;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_LDC;
+ ops : 2;
+- optypes : (ot_reg32,ot_reg32,ot_none,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_none,ot_none,ot_none,ot_none);
+ code : #209#192#1#17#65;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_LDM;
+ ops : 2;
+- optypes : (ot_memoryam4,ot_reglist,ot_none,ot_none);
++ 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_arm7
++ 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_reg32,ot_memoryam2,ot_none,ot_none);
+- code : #23#7#16;
+- flags : if_arm7
++ 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_reg32,ot_memoryam2,ot_none,ot_none);
+- code : #23#5#16;
+- flags : if_arm7
++ 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_reg32,ot_immediate or ot_bits32,ot_none,ot_none);
+- code : #34#80#176;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_none,ot_none);
+- code : #35#80#176;
+- flags : if_arm7
++ 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 : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none);
+- code : #36#80#176;
+- flags : if_arm7
++ 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 : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
+- code : #37#16#176;
+- flags : if_arm7
++ 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_reg32,ot_immediate or ot_bits32,ot_none,ot_none);
+- code : #34#80#208;
+- flags : if_arm7
++ 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_reg32,ot_none,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_LDRSB;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none,ot_none);
+ code : #36#80#208;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_LDRSB;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none);
+ code : #37#16#208;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_LDRSH;
+ ops : 2;
+- optypes : (ot_reg32,ot_immediate or ot_bits32,ot_none,ot_none);
+- code : #34#80#240;
+- flags : if_arm7
++ 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_reg32,ot_none,ot_none);
+- code : #35#80#240;
+- flags : if_arm7
++ 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 : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none);
+- code : #36#80#240;
+- flags : if_arm7
++ 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_LDRSH;
+- ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
+- code : #37#16#240;
+- flags : if_arm7
++ 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_LFM;
+- ops : 3;
+- optypes : (ot_reg32,ot_immediate or ot_bits8,ot_fpureg,ot_none);
+- code : #240#2#1;
+- flags : if_fpa
++ 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);
+- code : #21#0#32#144;
+- flags : if_arm7
++ 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_reg32,ot_none,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_MSR;
+ ops : 2;
+- optypes : (ot_reg32,ot_reg32,ot_none,ot_none);
+- code : #17#1#41#240;
+- flags : if_arm7
++ 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);
+- code : #18#1#40#240;
+- flags : if_arm7
++ 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_immediate,ot_none,ot_none);
+- code : #19#3#40#240;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_reg32,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_MVF;
+ ops : 2;
+- optypes : (ot_fpureg,ot_fpureg,ot_none,ot_none);
+- code : #242;
+- flags : if_fpa
++ 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_immediatefpu,ot_none,ot_none);
+- code : #242;
+- flags : if_fpa
++ 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_reg32,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_ORR;
+ ops : 4;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none);
+ code : #5#1#128;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_ORR;
+ 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#128;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_ORR;
+ 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#128;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #4#0#96;
+- flags : if_arm7
++ 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_reg32);
+- code : #5#0#96;
+- flags : if_arm7
++ 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_immediate);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none);
+ code : #6#0#96;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_RSB;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none);
+- code : #7#2#96;
+- flags : if_arm7
++ 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);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none);
+ code : #4#0#224;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_RSC;
+ ops : 4;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none);
+ code : #5#0#224;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_RSC;
+ 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#224;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_RSC;
+ 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#224;
+- flags : if_arm7
++ 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_reg32,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_SBC;
+ ops : 4;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none);
+ code : #5#0#192;
+- flags : if_arm7
++ 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_immediate);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none);
+ code : #6#0#192;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_SBC;
+ 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#192;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_SFM;
+ 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_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);
+- code : #22#0#224#144;
+- flags : if_arm7
++ 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);
+- code : #22#0#192#144;
+- flags : if_arm7
++ 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_memoryam4,ot_reglist,ot_none,ot_none);
++ 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_arm7
++ 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);
++ optypes : (ot_reg32,ot_memoryam2,ot_none,ot_none,ot_none,ot_none);
+ code : #23#4#0;
+- flags : if_arm7
++ 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_reg32,ot_memoryam2,ot_none,ot_none);
+- code : #23#6#0;
+- flags : if_arm7
++ 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_reg32,ot_immediate or ot_bits32,ot_none,ot_none);
+- code : #34#64#176;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_none,ot_none);
+- code : #35#64#176;
+- flags : if_arm7
++ 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 : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate or ot_bits32,ot_none);
+- code : #36#64#176;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_reg32,ot_none);
+- code : #37#0#176;
+- flags : if_arm7
++ 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_reg32,ot_reg32,ot_shifterop,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_SUB;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none);
+ code : #4#0#64;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_SUB;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none);
+ code : #4#0#64;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+- opcode : A_SWI;
+- ops : 1;
+- optypes : (ot_immediate,ot_none,ot_none,ot_none);
+- code : #2#15;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #39#1#144;
+- flags : if_arm7
++ 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_reg32,ot_none);
+- code : #39#1#144;
+- flags : if_arm7
++ 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_reg32,ot_none,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TEQ;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none);
+ code : #13#1#32;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TEQ;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none);
+ code : #14#1#32;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TEQ;
+ ops : 2;
+- optypes : (ot_reg32,ot_immediate,ot_none,ot_none);
++ optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none);
+ code : #15#3#32;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TST;
+ ops : 2;
+- optypes : (ot_reg32,ot_reg32,ot_none,ot_none);
++ 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_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TST;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_reg32,ot_none,ot_none,ot_none);
+ code : #13#1#0;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TST;
+ ops : 3;
+- optypes : (ot_reg32,ot_reg32,ot_immediate,ot_none);
++ optypes : (ot_reg32,ot_reg32,ot_shifterop,ot_none,ot_none,ot_none);
+ code : #14#1#0;
+- flags : if_arm7
++ flags : if_arm32 or if_armv4
+ ),
+ (
+ opcode : A_TST;
+ ops : 2;
+- optypes : (ot_reg32,ot_immediate,ot_none,ot_none);
++ optypes : (ot_reg32,ot_immediateshifter,ot_none,ot_none,ot_none,ot_none);
+ code : #15#3#0;
+- flags : if_arm7
++ 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);
+- code : #22#0#160#144;
+- flags : if_arm7
++ 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);
+- code : #22#0#128#144;
+- flags : if_arm7
++ 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_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_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_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_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_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_VNMLA;
++ ops : 3;
++ 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_VNMLA;
++ ops : 3;
++ 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_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_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_VNMUL;
++ ops : 3;
++ 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_VNMUL;
++ ops : 3;
++ 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_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_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_VFMS;
++ ops : 3;
++ 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_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_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_VFNMA;
++ ops : 3;
++ 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_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_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_VNEG;
++ ops : 2;
++ 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_VNEG;
++ ops : 2;
++ 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_VSQRT;
++ ops : 2;
++ 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_VSQRT;
++ ops : 2;
++ 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_VSUB;
++ ops : 3;
++ 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_VSUB;
++ ops : 3;
++ 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_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_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_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_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_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_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_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_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_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_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_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_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none);
++ code : #161#1#21;
++ flags : if_arm32 or if_fpa
++ ),
++ (
++ opcode : A_TAN;
++ ops : 2;
++ 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_SQT;
++ ops : 2;
++ 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_SQT;
++ ops : 2;
++ 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_SUF;
++ ops : 3;
++ 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_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_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_RSF;
++ ops : 3;
++ 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_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_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_POL;
++ ops : 3;
++ 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_POL;
++ ops : 3;
++ 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_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_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_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_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_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_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_RMF;
++ ops : 3;
++ 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_RPW;
++ ops : 3;
++ 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_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_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_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_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none);
++ code : #161#0#2;
++ flags : if_arm32 or if_fpa
++ ),
++ (
++ opcode : A_MUF;
++ ops : 3;
++ 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_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_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_ACS;
++ ops : 2;
++ 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_ACS;
++ ops : 2;
++ 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_ASN;
++ ops : 2;
++ 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_ASN;
++ ops : 2;
++ 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_ATN;
++ ops : 2;
++ 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_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_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_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_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_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_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_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_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none);
++ code : #161#0#8;
++ flags : if_arm32 or if_fpa
++ ),
++ (
++ opcode : A_DVF;
++ ops : 3;
++ 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_EXP;
++ ops : 2;
++ 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_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_fpureg,ot_fpureg,ot_fpureg,ot_none,ot_none,ot_none);
++ code : #161#0#20;
++ flags : if_arm32 or if_fpa
++ ),
++ (
++ opcode : A_FDV;
++ ops : 3;
++ 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_FLT;
++ ops : 2;
++ 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_FIX;
++ ops : 2;
++ 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_FML;
++ ops : 3;
++ 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_FML;
++ ops : 3;
++ 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_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_fpureg,ot_fpureg,ot_none,ot_none,ot_none,ot_none);
++ code : #161#1#13;
++ flags : if_arm32 or if_fpa
++ ),
++ (
++ 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_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
+ )
+ );
+Index: fpc/fpcsrc/compiler/arm/cgcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/cgcpu.pas
++++ fpc/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.cputype<cpu_armv6) then
++ {if (current_settings.cputype<cpu_armv6) then
+ postfix:=PF_IAX
+ else
+- postfix:=PF_IAD;
+- list.concat(setoppostfix(taicpu.op_ref_regset(A_FSTM,ref,R_MMREGISTER,R_SUBFD,mmregs),postfix));
++ postfix:=PF_IAD;}
++ list.concat(taicpu.op_ref_regset(A_VSTM,ref,R_MMREGISTER,R_SUBFD,mmregs));
+ end;
+ end;
+ end;
+@@ -2133,11 +2133,11 @@ unit cgcpu;
+ ref.index:=ref.base;
+ ref.base:=NR_NO;
+ { FLDMX is deprecated on ARMv6 and later }
+- if (current_settings.cputype<cpu_armv6) then
++ {if (current_settings.cputype<cpu_armv6) then
+ mmpostfix:=PF_IAX
+ else
+- mmpostfix:=PF_IAD;
+- list.concat(setoppostfix(taicpu.op_ref_regset(A_FLDM,ref,R_MMREGISTER,R_SUBFD,mmregs),mmpostfix));
++ mmpostfix:=PF_IAD;}
++ list.concat(taicpu.op_ref_regset(A_VLDM,ref,R_MMREGISTER,R_SUBFD,mmregs));
+ end;
+ end;
+ end;
+@@ -2934,8 +2934,8 @@ unit cgcpu;
+ function get_scalar_mm_op(fromsize,tosize : tcgsize) : tasmop;
+ const
+ convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of tasmop = (
+- (A_FCPYS,A_FCVTSD,A_NONE,A_NONE,A_NONE),
+- (A_FCVTDS,A_FCPYD,A_NONE,A_NONE,A_NONE),
++ (A_VMOV,A_VCVT,A_NONE,A_NONE,A_NONE),
++ (A_VCVT,A_VMOV,A_NONE,A_NONE,A_NONE),
+ (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
+ (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE),
+ (A_NONE,A_NONE,A_NONE,A_NONE,A_NONE));
+@@ -2946,33 +2946,30 @@ unit cgcpu;
+ end;
+
+
++ function get_scalar_mm_prefix(fromsize,tosize : tcgsize) : TOpPostfix;
++ const
++ convertop : array[OS_F32..OS_F128,OS_F32..OS_F128] of TOpPostfix = (
++ (PF_F32, PF_F32F64,PF_None,PF_None,PF_None),
++ (PF_F64F32,PF_F64, PF_None,PF_None,PF_None),
++ (PF_None, PF_None, PF_None,PF_None,PF_None),
++ (PF_None, PF_None, PF_None,PF_None,PF_None),
++ (PF_None, PF_None, PF_None,PF_None,PF_None));
++ begin
++ result:=convertop[fromsize,tosize];
++ end;
++
++
+ procedure tbasecgarm.a_loadmm_reg_reg(list: tasmlist; fromsize,tosize: tcgsize; reg1,reg2: tregister; shuffle: pmmshuffle);
+ var
+ instr: taicpu;
+ begin
+- if shuffle=nil then
+- begin
+- if fromsize=tosize then
+- { needs correct size in case of spilling }
+- case fromsize of
+- OS_F32:
+- instr:=taicpu.op_reg_reg(A_FCPYS,reg2,reg1);
+- OS_F64:
+- instr:=taicpu.op_reg_reg(A_FCPYD,reg2,reg1);
+- else
+- internalerror(2009112405);
+- end
+- else
+- internalerror(2009112406);
+- end
+- else if shufflescalar(shuffle) then
+- instr:=taicpu.op_reg_reg(get_scalar_mm_op(tosize,fromsize),reg2,reg1)
++ if (shuffle=nil) or shufflescalar(shuffle) then
++ instr:=setoppostfix(taicpu.op_reg_reg(get_scalar_mm_op(tosize,fromsize),reg2,reg1),get_scalar_mm_prefix(tosize,fromsize))
+ else
+ internalerror(2009112407);
+ list.concat(instr);
+ case instr.opcode of
+- A_FCPYS,
+- A_FCPYD:
++ A_VMOV:
+ add_move_instruction(instr);
+ end;
+ end;
+@@ -2983,7 +2980,6 @@ unit cgcpu;
+ intreg,
+ tmpmmreg : tregister;
+ reg64 : tregister64;
+- op : tasmop;
+ begin
+ if assigned(shuffle) and
+ not(shufflescalar(shuffle)) then
+@@ -3032,15 +3028,7 @@ unit cgcpu;
+ end
+ else
+ begin
+- case fromsize of
+- OS_F32:
+- op:=A_FLDS;
+- OS_F64:
+- op:=A_FLDD;
+- else
+- internalerror(2009112415);
+- end;
+- handle_load_store(list,op,PF_None,tmpmmreg,ref);
++ handle_load_store(list,A_VLDR,PF_None,tmpmmreg,ref);
+ end;
+
+ if (tmpmmreg<>reg) 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;
+
+
+Index: fpc/fpcsrc/compiler/arm/cpubase.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/cpubase.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/arm/cpuelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/cpuelf.pas
++++ fpc/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;
+
+Index: fpc/fpcsrc/compiler/arm/cpuinfo.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/cpuinfo.pas
++++ fpc/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],
+Index: fpc/fpcsrc/compiler/arm/narmadd.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/narmadd.pas
++++ fpc/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:
+Index: fpc/fpcsrc/compiler/arm/narmcnv.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/narmcnv.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/arm/narminl.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/narminl.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/arm/narmmat.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/narmmat.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/arm/narmmem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/narmmem.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/arm/raarmgas.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/raarmgas.pas
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/arm/rarmcon.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmcon.inc
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/arm/rarmdwa.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmdwa.inc
++++ fpc/fpcsrc/compiler/arm/rarmdwa.inc
+@@ -122,4 +122,11 @@
+ 0,
+ 0,
+ 0,
++0,
++0,
++0,
++0,
++0,
++0,
++0,
+ 0
+Index: fpc/fpcsrc/compiler/arm/rarmnor.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmnor.inc
++++ fpc/fpcsrc/compiler/arm/rarmnor.inc
+@@ -1,2 +1,2 @@
+ { don't edit, this file is generated from armreg.dat }
+-124
++131
+Index: fpc/fpcsrc/compiler/arm/rarmnum.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmnum.inc
++++ fpc/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)
+Index: fpc/fpcsrc/compiler/arm/rarmrni.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmrni.inc
++++ fpc/fpcsrc/compiler/arm/rarmrni.inc
+@@ -122,4 +122,11 @@
+ 120,
+ 121,
+ 122,
+-123
++123,
++124,
++125,
++126,
++127,
++128,
++129,
++130
+Index: fpc/fpcsrc/compiler/arm/rarmsri.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmsri.inc
++++ fpc/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,
+Index: fpc/fpcsrc/compiler/arm/rarmsta.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmsta.inc
++++ fpc/fpcsrc/compiler/arm/rarmsta.inc
+@@ -122,4 +122,11 @@
+ 0,
+ 0,
+ 0,
++0,
++0,
++0,
++0,
++0,
++0,
++0,
+ 0
+Index: fpc/fpcsrc/compiler/arm/rarmstd.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmstd.inc
++++ fpc/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'
+Index: fpc/fpcsrc/compiler/arm/rarmsup.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/arm/rarmsup.inc
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/assemble.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/assemble.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/cgbase.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/cgbase.pas
++++ fpc/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',
+Index: fpc/fpcsrc/compiler/cghlcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/cghlcpu.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/cgobj.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/cgobj.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/cgutils.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/cgutils.pas
++++ fpc/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}
+Index: fpc/fpcsrc/compiler/fpcdefs.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/fpcdefs.inc
++++ fpc/fpcsrc/compiler/fpcdefs.inc
+@@ -242,6 +242,7 @@
+ {$define cpurox}
+ {$define cputargethasfixedstack}
+ {$define cpurefshaveindexreg}
++ {$define SUPPORT_GET_FRAME}
+ {$endif aarch64}
+
+ {$IFDEF MACOS}
+Index: fpc/fpcsrc/compiler/hlcg2ll.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/hlcg2ll.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/hlcgobj.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/hlcgobj.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/i386/cpuelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/i386/cpuelf.pas
++++ fpc/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 =
+Index: fpc/fpcsrc/compiler/i8086/n8086mem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/i8086/n8086mem.pas
++++ fpc/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;
+
+Index: fpc/fpcsrc/compiler/jvm/hlcgcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/jvm/hlcgcpu.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/m68k/n68kmem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/m68k/n68kmem.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/mips/cpuelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/mips/cpuelf.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/msg/errore.msg
+===================================================================
+--- fpc.orig/fpcsrc/compiler/msg/errore.msg
++++ fpc/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<x>_Set target CPU (arm,avr,i386,jvm
+ 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<x>_Set target CPU (arm,avr,i386,jvm
+ 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 (W
+ 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 (
+ 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 (
+ 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; s
+ 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<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)
++4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)
++a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)
+ A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)
+ 3*2WR_Generate relocation code (Windows)
+ 4*2WR_Generate relocation code (Windows)
+Index: fpc/fpcsrc/compiler/msgidx.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/msgidx.inc
++++ fpc/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,
+Index: fpc/fpcsrc/compiler/ncal.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncal.pas
++++ fpc/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;
+-
+- { determine the type of the parameters }
+- if assigned(left) then
+- begin
+- tcallparanode(left).get_paratype;
+- if codegenerror then
+- goto errorexit;
+- end;
+-
+- if assigned(methodpointer) then
+- typecheckpass(methodpointer);
++ try
++ { determine length of parameter list }
++ pt:=tcallparanode(left);
++ paralength:=0;
++ while assigned(pt) do
++ begin
++ inc(paralength);
++ pt:=tcallparanode(pt.right);
++ end;
+
+- { procedure variable ? }
+- if assigned(right) then
+- begin
+- set_varstate(right,vs_read,[vsf_must_be_valid]);
+- typecheckpass(right);
++ { determine the type of the parameters }
++ if assigned(left) then
++ begin
++ tcallparanode(left).get_paratype;
+ if codegenerror then
+- exit;
++ exit;
++ end;
+
+- procdefinition:=tabstractprocdef(right.resultdef);
++ if assigned(methodpointer) then
++ typecheckpass(methodpointer);
+
+- { 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,'<Procedure Variable>');
+- goto errorexit;
+- end;
++ { 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);
++
++ { 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,'<Procedure Variable>');
+- 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,'<Procedure Variable>');
++ 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,'<Procedure Variable>');
++ 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));
+-
+- { 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);
++ { 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);
+ {$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);
+-
+- { 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);
++ { 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 needed default parameters }
+- if (paralength<procdefinition.maxparacount) then
+- begin
+- paraidx:=0;
+- i:=0;
+- while (i<paralength) do
+- begin
+- if paraidx>=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) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
+- inc(paraidx);
+- while (paraidx<procdefinition.paras.count) do
+- begin
+- if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
+- internalerror(200212142);
+- left:=ccallparanode.create(genconstsymtree(
+- tconstsym(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)),left);
+- { Ignore vs_hidden parameters }
+- repeat
++ { add needed default parameters }
++ if (paralength<procdefinition.maxparacount) then
++ begin
++ paraidx:=0;
++ i:=0;
++ while (i<paralength) do
++ begin
++ if 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;
+-
+- { recursive call? }
+- if assigned(current_procinfo) and
+- (procdefinition=current_procinfo.procdef) then
+- include(current_procinfo.flags,pi_is_recursive);
++ end;
++ while (paraidx<procdefinition.paras.count) and (vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions) do
++ inc(paraidx);
++ while (paraidx<procdefinition.paras.count) do
++ begin
++ if not assigned(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym) then
++ internalerror(200212142);
++ left:=ccallparanode.create(genconstsymtree(
++ tconstsym(tparavarsym(procdefinition.paras[paraidx]).defaultconstsym)),left);
++ { Ignore vs_hidden parameters }
++ repeat
++ inc(paraidx);
++ until (paraidx>=procdefinition.paras.count) or
++ not(vo_is_hidden_para in tparavarsym(procdefinition.paras[paraidx]).varoptions);
++ end;
++ end;
+
+- { 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;
++
++ { 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;
++
++ { 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;
++
++ { 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);
++ { 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);
++
++ { set the appropriate node flag if the call never returns }
++ if po_noreturn in procdefinition.procoptions then
++ include(callnodeflags,cnf_call_never_returns);
++
++ { 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;
++
++ { bind parasyms to the callparanodes and insert hidden parameters }
++ bind_parasym;
++
++ { insert type conversions for parameters }
++ if assigned(left) then
++ tcallparanode(left).insert_typeconv;
+
+- if methodpointer.nodetype<>typen then
++ { dispinterface methode invoke? }
++ if assigned(methodpointer) and is_dispinterface(methodpointer.resultdef) 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,[])
++ case procdefinition.proctypeoption of
++ potype_propgetter: calltype:=dct_propget;
++ potype_propsetter: calltype:=dct_propput;
+ else
+- set_varstate(methodpointer,vs_read,[vsf_must_be_valid]);
+- 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;
+-
+- { 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);
+-
+- { set the appropriate node flag if the call never returns }
+- if po_noreturn in procdefinition.procoptions then
+- include(callnodeflags,cnf_call_never_returns);
+-
+- { 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;
+-
+- { bind parasyms to the callparanodes and insert hidden parameters }
+- bind_parasym;
+-
+- { insert type conversions for parameters }
+- if assigned(left) then
+- tcallparanode(left).insert_typeconv;
++ 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);
+
+- { 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;
++ { don't free reused nodes }
++ methodpointer:=nil;
++ parameters:=nil;
+ 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);
+
+- { don't free reused nodes }
+- methodpointer:=nil;
+- parameters:=nil;
+- end;
+-
+- errorexit:
+- aktcallnode:=oldcallnode;
++ 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;
++ oldcallnode:=aktcallnode;
++ aktcallnode:=self;
+
+- { 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;
++ 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;
+
+- { 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;
+-
+- { 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;
++ { 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;
+
+- { 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;
++ { 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;
++
++ { 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;
++
++ { 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;
+
+
+Index: fpc/fpcsrc/compiler/ncgcnv.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncgcnv.pas
++++ fpc/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 }
+Index: fpc/fpcsrc/compiler/ncginl.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncginl.pas
++++ fpc/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;
+
+
+Index: fpc/fpcsrc/compiler/ncgld.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncgld.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/ncgmat.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncgmat.pas
++++ fpc/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 }
+Index: fpc/fpcsrc/compiler/ncgmem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncgmem.pas
++++ fpc/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 p<w>char(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;
+Index: fpc/fpcsrc/compiler/ncgutil.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncgutil.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/ncnv.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ncnv.pas
++++ fpc/fpcsrc/compiler/ncnv.pas
+@@ -2375,6 +2375,10 @@ implementation
+ (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
+ not(is_array_of_const(left.resultdef)) and
+@@ -2388,10 +2392,6 @@ implementation
+ { the softfloat code generates casts <const. float> 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)
+Index: fpc/fpcsrc/compiler/ninl.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ninl.pas
++++ fpc/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
+Index: fpc/fpcsrc/compiler/nld.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/nld.pas
++++ fpc/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 }
+Index: fpc/fpcsrc/compiler/nmem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/nmem.pas
++++ fpc/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;
+
+Index: fpc/fpcsrc/compiler/objcgutl.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/objcgutl.pas
++++ fpc/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,
+Index: fpc/fpcsrc/compiler/objcutil.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/objcutil.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/ogbase.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ogbase.pas
++++ fpc/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;
+
+
+Index: fpc/fpcsrc/compiler/ogcoff.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ogcoff.pas
++++ fpc/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: '$';
+Index: fpc/fpcsrc/compiler/ogelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ogelf.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/options.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/options.pas
++++ fpc/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}
+Index: fpc/fpcsrc/compiler/pparautl.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/pparautl.pas
++++ fpc/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 ? }
+Index: fpc/fpcsrc/compiler/ppu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/ppu.pas
++++ fpc/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}
+
+Index: fpc/fpcsrc/compiler/psub.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/psub.pas
++++ fpc/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 }
+Index: fpc/fpcsrc/compiler/psystem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/psystem.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/raatt.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/raatt.pas
++++ fpc/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 .<dt> 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;
+Index: fpc/fpcsrc/compiler/rautils.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/rautils.pas
++++ fpc/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:
+ ;
+Index: fpc/fpcsrc/compiler/sparc/cpuelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/sparc/cpuelf.pas
++++ fpc/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 =
+Index: fpc/fpcsrc/compiler/symdef.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/symdef.pas
++++ fpc/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}
+Index: fpc/fpcsrc/compiler/systems/i_bsd.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems/i_bsd.pas
++++ fpc/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.
+Index: fpc/fpcsrc/compiler/systems/i_linux.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems/i_linux.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/systems/i_win.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems/i_win.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/systems/t_bsd.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems/t_bsd.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/systems/t_linux.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems/t_linux.pas
++++ fpc/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);
+Index: fpc/fpcsrc/compiler/systems.inc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems.inc
++++ fpc/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
+ );
+
+
+Index: fpc/fpcsrc/compiler/systems.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/systems.pas
++++ fpc/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;
+
+
+Index: fpc/fpcsrc/compiler/tgobj.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/tgobj.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/utils/Makefile.fpc
+===================================================================
+--- fpc.orig/fpcsrc/compiler/utils/Makefile.fpc
++++ fpc/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]
+Index: fpc/fpcsrc/compiler/utils/fpc.pp
+===================================================================
+--- fpc.orig/fpcsrc/compiler/utils/fpc.pp
++++ fpc/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'
+Index: fpc/fpcsrc/compiler/utils/mka64ins.pp
+===================================================================
+--- fpc.orig/fpcsrc/compiler/utils/mka64ins.pp
++++ fpc/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;
+
+Index: fpc/fpcsrc/compiler/utils/mkarmins.pp
+===================================================================
+--- fpc.orig/fpcsrc/compiler/utils/mkarmins.pp
++++ fpc/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,' )');
+Index: fpc/fpcsrc/compiler/utils/ppuutils/ppudump.pp
+===================================================================
+--- fpc.orig/fpcsrc/compiler/utils/ppuutils/ppudump.pp
++++ fpc/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
+Index: fpc/fpcsrc/compiler/version.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/version.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/x86/agx86att.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/x86/agx86att.pas
++++ fpc/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 : '# ';
+Index: fpc/fpcsrc/compiler/x86/cgx86.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/x86/cgx86.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/x86/nx86mem.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/x86/nx86mem.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/x86_64/cgcpu.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/x86_64/cgcpu.pas
++++ fpc/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;
+Index: fpc/fpcsrc/compiler/x86_64/cpuelf.pas
+===================================================================
+--- fpc.orig/fpcsrc/compiler/x86_64/cpuelf.pas
++++ fpc/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;
+ );
+
+
+Index: fpc/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake
++++ fpc/fpcsrc/packages/fcl-res/Makefile.fpc.fpcmake
+@@ -13,7 +13,7 @@ units=acceleratorsresource bitmapresourc
+ 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
+
+
+Index: fpc/fpcsrc/packages/fcl-res/src/elfconsts.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/elfconsts.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/elfdefaulttarget.inc
++++ fpc/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}
+Index: fpc/fpcsrc/packages/fcl-res/src/elfreader.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/elfreader.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fcl-res/src/elfsubwriter.inc
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/elfsubwriter.inc
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fcl-res/src/elfwriter.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/elfwriter.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fcl-res/src/machoconsts.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machoconsts.pp
++++ fpc/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.
+Index: fpc/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machodefaulttarget.inc
++++ fpc/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}
+Index: fpc/fpcsrc/packages/fcl-res/src/machoreader.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machoreader.pp
++++ fpc/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;
+
+Index: fpc/fpcsrc/packages/fcl-res/src/machosubwriter.inc
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machosubwriter.inc
++++ fpc/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
+Index: fpc/fpcsrc/packages/fcl-res/src/machotypes.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machotypes.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fcl-res/src/machowriter.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fcl-res/src/machowriter.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/fpmkunit/src/fpmkunit.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/fpmkunit/src/fpmkunit.pp
++++ fpc/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;
+
+Index: fpc/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake
+===================================================================
+--- fpc.orig/fpcsrc/packages/iosxlocale/Makefile.fpc.fpcmake
++++ fpc/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
+Index: fpc/fpcsrc/packages/iosxlocale/fpmake.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/iosxlocale/fpmake.pp
++++ fpc/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;
+Index: fpc/fpcsrc/packages/iosxlocale/src/iosxwstr.pp
+===================================================================
+--- /dev/null
++++ fpc/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 convertedchars<strlen then
++ begin
++ setlength(dest,encodedlen);
++ { try again }
++ convertedchars:=CFStringGetBytes(str,range,cfcp,ByteParameter('?'),false,UInt8Ptr(dest),encodedlen,encodedlen);
++ { failed again ? }
++ if convertedchars<>strlen 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<maxlookahead) do
++ begin
++ inc(result);
++ cfstr:=CFStringCreateWithBytesNoCopy(nil,UnivPtr(Str),result,cfcp,false,kCFAllocatorNull);
++ if assigned(cfstr) then
++ begin
++ CFRelease(cfstr);
++ exit;
++ end;
++ end;
++ result:=-1;
++ end;
++
++
++ function CharLengthPChar(const Str: PChar): PtrInt;
++ var
++ cfstr: CFStringRef;
++ cfcp: CFStringEncoding;
++ s: PChar;
++ tmplen: PtrInt;
++ begin
++ result:=0;
++ if str[0]=#0 then
++ exit;
++ cfcp:=get_cfencoding_for_cp(DefaultSystemCodePage);
++ if cfcp=kCFStringEncodingInvalidId then
++ begin
++ { or -1? }
++ result:=strlen(Str);
++ exit
++ end;
++ s:=str;
++ repeat
++ tmplen:=InternalCodePointLength(s,cfcp,8);
++ { invalid -> 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.
+Index: fpc/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc
+===================================================================
+--- fpc.orig/fpcsrc/packages/rtl-extra/src/linux/unixsock.inc
++++ fpc/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}
+
+Index: fpc/fpcsrc/packages/rtl-extra/src/unix/ipc.pp
+===================================================================
+--- fpc.orig/fpcsrc/packages/rtl-extra/src/unix/ipc.pp
++++ fpc/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}
+Index: fpc/fpcsrc/rtl/aarch64/aarch64.inc
+===================================================================
+--- /dev/null
++++ fpc/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}
+Index: fpc/fpcsrc/rtl/aarch64/int64p.inc
+===================================================================
+--- /dev/null
++++ fpc/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 }
+Index: fpc/fpcsrc/rtl/aarch64/makefile.cpu
+===================================================================
+--- /dev/null
++++ fpc/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))
++#
+Index: fpc/fpcsrc/rtl/aarch64/math.inc
+===================================================================
+--- /dev/null
++++ fpc/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}
++
++
+Index: fpc/fpcsrc/rtl/aarch64/mathu.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/aarch64/set.inc
+===================================================================
+--- /dev/null
++++ fpc/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.
++
++ **********************************************************************}
++
+Index: fpc/fpcsrc/rtl/aarch64/setjump.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
++
++
+Index: fpc/fpcsrc/rtl/aarch64/setjumph.inc
+===================================================================
+--- /dev/null
++++ fpc/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'];
++
+Index: fpc/fpcsrc/rtl/aarch64/strings.inc
+===================================================================
+--- /dev/null
++++ fpc/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.
++
++ **********************************************************************}
++
+Index: fpc/fpcsrc/rtl/aarch64/stringss.inc
+===================================================================
+--- /dev/null
++++ fpc/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.
++
++ **********************************************************************}
++
++
+Index: fpc/fpcsrc/rtl/arm/arm.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/arm/arm.inc
++++ fpc/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}
+Index: fpc/fpcsrc/rtl/arm/thumb2.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/arm/thumb2.inc
++++ fpc/fpcsrc/rtl/arm/thumb2.inc
+@@ -15,7 +15,7 @@
+
+ **********************************************************************}
+
+-{$asmmode gas}
++{$asmmode divided}
+
+ {$ifndef FPC_SYSTEM_HAS_MOVE}
+ {$define FPC_SYSTEM_FPC_MOVE}
+Index: fpc/fpcsrc/rtl/bsd/ostypes.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/bsd/ostypes.inc
++++ fpc/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;
+
+Index: fpc/fpcsrc/rtl/darwin/aarch64/sig_cpu.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
++
++
+Index: fpc/fpcsrc/rtl/darwin/aarch64/sighnd.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
++
+Index: fpc/fpcsrc/rtl/darwin/extres_multiarch.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/darwin/extres_multiarch.inc
++++ fpc/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
+Index: fpc/fpcsrc/rtl/darwin/ptypes.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/darwin/ptypes.inc
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/darwin/signal.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/darwin/signal.inc
++++ fpc/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}
+Index: fpc/fpcsrc/rtl/inc/ctypes.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/inc/ctypes.pp
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/inc/objc.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/inc/objc.pp
++++ fpc/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}
+
+Index: fpc/fpcsrc/rtl/inc/objcnf.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/inc/objcnf.inc
++++ fpc/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;
+
+Index: fpc/fpcsrc/rtl/inc/system.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/inc/system.inc
++++ fpc/fpcsrc/rtl/inc/system.inc
+@@ -264,6 +264,13 @@ function do_isdevice(handle:thandle):boo
+ {$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 !}
+Index: fpc/fpcsrc/rtl/inc/systemh.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/inc/systemh.inc
++++ fpc/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): QWo
+ {$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;c
+ {$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 : Int
+ {$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}
+Index: fpc/fpcsrc/rtl/linux/aarch64/bsyscall.inc
+===================================================================
+--- /dev/null
++++ fpc/fpcsrc/rtl/linux/aarch64/bsyscall.inc
+@@ -0,0 +1 @@
++{ nothing }
+Index: fpc/fpcsrc/rtl/linux/aarch64/cprt0.as
+===================================================================
+--- /dev/null
++++ fpc/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
+Index: fpc/fpcsrc/rtl/linux/aarch64/dllprt0.as
+===================================================================
+--- /dev/null
++++ fpc/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
+Index: fpc/fpcsrc/rtl/linux/aarch64/gprt0.as
+===================================================================
+--- /dev/null
++++ fpc/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
+Index: fpc/fpcsrc/rtl/linux/aarch64/prt0.as
+===================================================================
+--- /dev/null
++++ fpc/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
+Index: fpc/fpcsrc/rtl/linux/aarch64/sighnd.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/aarch64/sighndh.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/aarch64/stat.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/aarch64/syscall.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/aarch64/syscallh.inc
+===================================================================
+--- /dev/null
++++ fpc/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';
+Index: fpc/fpcsrc/rtl/linux/aarch64/sysnr.inc
+===================================================================
+--- /dev/null
++++ fpc/fpcsrc/rtl/linux/aarch64/sysnr.inc
+@@ -0,0 +1 @@
++{$i ../sysnr-gen.inc}
+Index: fpc/fpcsrc/rtl/linux/bunxsysc.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/bunxsysc.inc
++++ fpc/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:pc
+ 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,writefd
+ 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):
+ }
+
+ 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
+ }
+
+ 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'];
+Index: fpc/fpcsrc/rtl/linux/linux.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/linux.pp
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/oldlinux.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/oldlinux.pp
++++ fpc/fpcsrc/rtl/linux/oldlinux.pp
+@@ -1924,9 +1924,16 @@ Function Sys_Mkdir(Filename:pchar;mode:l
+ 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):longi
+ 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;
+Index: fpc/fpcsrc/rtl/linux/osdefs.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/osdefs.inc
++++ fpc/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}
+Index: fpc/fpcsrc/rtl/linux/ossysc.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/ossysc.inc
++++ fpc/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 : sta
+
+ 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
+ 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
+ }
+
+ 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; amod
+ }
+
+ 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;
+
+
+Index: fpc/fpcsrc/rtl/linux/ostypes.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/ostypes.inc
++++ fpc/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)}
+Index: fpc/fpcsrc/rtl/linux/pmutext.inc
+===================================================================
+--- /dev/null
++++ fpc/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
+Index: fpc/fpcsrc/rtl/linux/ptypes.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/ptypes.inc
++++ fpc/fpcsrc/rtl/linux/ptypes.inc
+@@ -30,12 +30,21 @@ and all three 32-bit systems returned co
+ 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}
+Index: fpc/fpcsrc/rtl/linux/sysnr-gen.inc
+===================================================================
+--- /dev/null
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/linux/sysosh.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/sysosh.inc
++++ fpc/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}
+
+
+
+Index: fpc/fpcsrc/rtl/linux/termios.inc
+===================================================================
+--- fpc.orig/fpcsrc/rtl/linux/termios.inc
++++ fpc/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;
+Index: fpc/fpcsrc/rtl/unix/cthreads.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/unix/cthreads.pp
++++ fpc/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);
+Index: fpc/fpcsrc/rtl/unix/cwstring.pp
+===================================================================
+--- fpc.orig/fpcsrc/rtl/unix/cwstring.pp
++++ fpc/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
+Index: fpc/fpcsrc/utils/fpcm/fpcmmain.pp
+===================================================================
+--- fpc.orig/fpcsrc/utils/fpcm/fpcmmain.pp
++++ fpc/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','x86_64','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
+Index: fpc/fpcsrc/utils/fpcres/fpcres.pas
+===================================================================
+--- fpc.orig/fpcsrc/utils/fpcres/fpcres.pas
++++ fpc/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 <name> 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;
+Index: fpc/fpcsrc/utils/fpcres/target.pas
+===================================================================
+--- fpc.orig/fpcsrc/utils/fpcres/target.pas
++++ fpc/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;