From 26bbe7ac9b78db96023427e9dced8afeea3195af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aram=20H=C4=83v=C4=83rneanu?= Date: Sun, 8 Mar 2015 13:58:16 +0100 Subject: [PATCH] cmd/internal/obj, cmd/internal/obj/arm64: add support for GOARCH=arm64 ARM64 (ARMv8) has 32 general purpose, 64-bit integer registers (R0-R31), 32 64-bit scalar floating point registers (F0-F31), and 32 128-bit vector registers (unused, V0-V31). R31 is either the stack pointer (RSP), or the zero register (ZR), depending on the instruction. Note the distinction between the hardware stack pointer, RSP, and the virtual stack pointer SP. The (hardware) stack pointer must be 16-byte aligned at all times; the RSP register itself must be aligned, offset(RSP) only has to have natural alignment. Instructions are fixed-width, and are 32-bit wide. ARM64 supports ARMv7 too (32-bit ARM), but not in the same process. In general, there is not much in common between 32-bit ARM and ARM64, it's a new architecture. All implementations have floating point instructions. This change adds a Prog.To3 field analogous to Prog.To. It is used by exclusive load/store instructions such as STLXR which read from one register, and write to both a register and a memory address. STLXRW R1, (R0), R3 This will store the word contained in R1 to the memory address pointed by R0. R3 will be updated with the status result of the store. It is used to implement atomic operations. No other changes are made to the portable Prog and Addr structures. Change-Id: Ie839029aa5265bbad35769d9689eca11e1c48c47 Reviewed-on: https://go-review.googlesource.com/7046 Reviewed-by: Russ Cox --- src/cmd/internal/obj/arm64/7.out.go | 711 +++++ src/cmd/internal/obj/arm64/anames.go | 379 +++ src/cmd/internal/obj/arm64/anames7.go | 62 + src/cmd/internal/obj/arm64/asm7.go | 4194 +++++++++++++++++++++++++ src/cmd/internal/obj/arm64/list7.go | 114 + src/cmd/internal/obj/arm64/obj7.go | 829 +++++ src/cmd/internal/obj/arm64/util.go | 12 + src/cmd/internal/obj/link.go | 2 + src/cmd/internal/obj/util.go | 10 +- 9 files changed, 6309 insertions(+), 4 deletions(-) create mode 100644 src/cmd/internal/obj/arm64/7.out.go create mode 100644 src/cmd/internal/obj/arm64/anames.go create mode 100644 src/cmd/internal/obj/arm64/anames7.go create mode 100644 src/cmd/internal/obj/arm64/asm7.go create mode 100644 src/cmd/internal/obj/arm64/list7.go create mode 100644 src/cmd/internal/obj/arm64/obj7.go create mode 100644 src/cmd/internal/obj/arm64/util.go diff --git a/src/cmd/internal/obj/arm64/7.out.go b/src/cmd/internal/obj/arm64/7.out.go new file mode 100644 index 0000000000..67b37aae6f --- /dev/null +++ b/src/cmd/internal/obj/arm64/7.out.go @@ -0,0 +1,711 @@ +// cmd/7c/7.out.h from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/src/cmd/7c/7.out.h +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import "cmd/internal/obj" + +const ( + NSNAME = 8 + NSYM = 50 + NREG = 32 /* number of general registers */ + NFREG = 32 /* number of floating point registers */ +) + +// General purpose registers, kept in the low bits of Prog.Reg. +const ( + // integer + REG_R0 = obj.RBaseARM64 + iota + REG_R1 + REG_R2 + REG_R3 + REG_R4 + REG_R5 + REG_R6 + REG_R7 + REG_R8 + REG_R9 + REG_R10 + REG_R11 + REG_R12 + REG_R13 + REG_R14 + REG_R15 + REG_R16 + REG_R17 + REG_R18 + REG_R19 + REG_R20 + REG_R21 + REG_R22 + REG_R23 + REG_R24 + REG_R25 + REG_R26 + REG_R27 + REG_R28 + REG_R29 + REG_R30 + REG_R31 + + // scalar floating point + REG_F0 + REG_F1 + REG_F2 + REG_F3 + REG_F4 + REG_F5 + REG_F6 + REG_F7 + REG_F8 + REG_F9 + REG_F10 + REG_F11 + REG_F12 + REG_F13 + REG_F14 + REG_F15 + REG_F16 + REG_F17 + REG_F18 + REG_F19 + REG_F20 + REG_F21 + REG_F22 + REG_F23 + REG_F24 + REG_F25 + REG_F26 + REG_F27 + REG_F28 + REG_F29 + REG_F30 + REG_F31 + + // SIMD + REG_V0 + REG_V1 + REG_V2 + REG_V3 + REG_V4 + REG_V5 + REG_V6 + REG_V7 + REG_V8 + REG_V9 + REG_V10 + REG_V11 + REG_V12 + REG_V13 + REG_V14 + REG_V15 + REG_V16 + REG_V17 + REG_V18 + REG_V19 + REG_V20 + REG_V21 + REG_V22 + REG_V23 + REG_V24 + REG_V25 + REG_V26 + REG_V27 + REG_V28 + REG_V29 + REG_V30 + REG_V31 + + // The EQ in + // CSET EQ, R0 + // is encoded as TYPE_REG, even though it's not really a register. + COND_EQ + COND_NE + COND_HS + COND_LO + COND_MI + COND_PL + COND_VS + COND_VC + COND_HI + COND_LS + COND_GE + COND_LT + COND_GT + COND_LE + COND_AL + COND_NV + + REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31 +) + +// Not registers, but flags that can be combined with regular register +// constants to indicate extended register conversion. When checking, +// you should subtract obj.RBaseARM64 first. From this difference, bit 11 +// indicates extended register, bits 8-10 select the conversion mode. +const REG_EXT = obj.RBaseARM64 + 1<<11 + +const ( + REG_UXTB = REG_EXT + iota<<8 + REG_UXTH + REG_UXTW + REG_UXTX + REG_SXTB + REG_SXTH + REG_SXTW + REG_SXTX +) + +// Special registers, after subtracting obj.RBaseARM64, bit 12 indicates +// a special register and the low bits select the register. +const ( + REG_SPECIAL = obj.RBaseARM64 + 1<<12 + iota + REG_DAIF + REG_NZCV + REG_FPSR + REG_FPCR + REG_SPSR_EL1 + REG_ELR_EL1 + REG_SPSR_EL2 + REG_ELR_EL2 + REG_CurrentEL + REG_SP_EL0 + REG_SPSel + REG_DAIFSet + REG_DAIFClr +) + +// Register assignments: +// +// compiler allocates R0 up as temps +// compiler allocates register variables R7-R25 +// compiler allocates external registers R26 down +// +// compiler allocates register variables F7-F26 +// compiler allocates external registers F26 down +const ( + REGMIN = REG_R7 // register variables allocated from here to REGMAX + REGRT1 = REG_R16 // ARM64 IP0, for external linker, runtime, duffzero and duffcopy + REGRT2 = REG_R17 // ARM64 IP1, for external linker, runtime, duffcopy + REGPR = REG_R18 // ARM64 platform register, unused in the Go toolchain + REGMAX = REG_R25 + + REGCTXT = REG_R26 // environment for closures + REGTMP = REG_R27 // reserved for liblink + REGG = REG_R28 // G + REGFP = REG_R29 // frame pointer, unused in the Go toolchain + REGLINK = REG_R30 + + // ARM64 uses R31 as both stack pointer and zero register, + // depending on the instruction. To differentiate RSP from ZR, + // we use a different numeric value for REGZERO and REGSP. + REGZERO = REG_R31 + REGSP = REG_RSP + + FREGRET = REG_F0 + FREGMIN = REG_F7 // first register variable + FREGMAX = REG_F26 // last register variable for 7g only + FREGEXT = REG_F26 // first external register + FREGZERO = REG_F28 // both float and double + FREGHALF = REG_F29 // double + FREGONE = REG_F30 // double + FREGTWO = REG_F31 // double +) + +const ( + BIG = 2048 - 8 +) + +const ( + /* mark flags */ + LABEL = 1 << iota + LEAF + FLOAT + BRANCH + LOAD + FCMP + SYNC + LIST + FOLL + NOSCHED +) + +const ( + C_NONE = iota + C_REG // R0..R30 + C_RSP // R0..R30, RSP + C_FREG // F0..F31 + C_VREG // V0..V31 + C_PAIR // (Rn, Rm) + C_SHIFT // Rn<<2 + C_EXTREG // Rn.UXTB<<3 + C_SPR // REG_NZCV + C_COND // EQ, NE, etc + + C_ZCON // $0 or ZR + C_ADDCON0 // 12-bit unsigned, unshifted + C_ADDCON // 12-bit unsigned, shifted left by 0 or 12 + C_MOVCON // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16 + C_BITCON // bitfield and logical immediate masks + C_ABCON // could be C_ADDCON or C_BITCON + C_MBCON // could be C_MOVCON or C_BITCON + C_LCON // 32-bit constant + C_VCON // 64-bit constant + C_FCON // floating-point constant + C_VCONADDR // 64-bit memory address + + C_AACON // ADDCON offset in auto constant $a(FP) + C_LACON // 32-bit offset in auto constant $a(FP) + C_AECON // ADDCON offset in extern constant $e(SB) + + // TODO(aram): only one branch class should be enough + C_SBRA // for TYPE_BRANCH + C_LBRA + + C_NPAUTO // -512 <= x < 0, 0 mod 8 + C_NSAUTO // -256 <= x < 0 + C_PSAUTO // 0 to 255 + C_PPAUTO // 0 to 504, 0 mod 8 + C_UAUTO4K // 0 to 4095 + C_UAUTO8K // 0 to 8190, 0 mod 2 + C_UAUTO16K // 0 to 16380, 0 mod 4 + C_UAUTO32K // 0 to 32760, 0 mod 8 + C_UAUTO64K // 0 to 65520, 0 mod 16 + C_LAUTO // any other 32-bit constant + + C_SEXT1 // 0 to 4095, direct + C_SEXT2 // 0 to 8190 + C_SEXT4 // 0 to 16380 + C_SEXT8 // 0 to 32760 + C_SEXT16 // 0 to 65520 + C_LEXT + + // TODO(aram): s/AUTO/INDIR/ + C_ZOREG // 0(R) + C_NPOREG // mirror NPAUTO, etc + C_NSOREG + C_PSOREG + C_PPOREG + C_UOREG4K + C_UOREG8K + C_UOREG16K + C_UOREG32K + C_UOREG64K + C_LOREG + + C_ADDR // TODO(aram): explain difference from C_VCONADDR + C_ROFF // register offset (including register extended) + + C_GOK + C_TEXTSIZE + C_NCLASS // must be last +) + +const ( + C_XPRE = 1 << 6 // match arm.C_WBIT, so Prog.String know how to print it + C_XPOST = 1 << 5 // match arm.C_PBIT, so Prog.String know how to print it +) + +//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm64 + +const ( + AADC = obj.ABaseARM64 + obj.A_ARCHSPECIFIC + iota + AADCS + AADCSW + AADCW + AADD + AADDS + AADDSW + AADDW + AADR + AADRP + AAND + AANDS + AANDSW + AANDW + AASR + AASRW + AAT + ABFI + ABFIW + ABFM + ABFMW + ABFXIL + ABFXILW + ABIC + ABICS + ABICSW + ABICW + ABRK + ACBNZ + ACBNZW + ACBZ + ACBZW + ACCMN + ACCMNW + ACCMP + ACCMPW + ACINC + ACINCW + ACINV + ACINVW + ACLREX + ACLS + ACLSW + ACLZ + ACLZW + ACMN + ACMNW + ACMP + ACMPW + ACNEG + ACNEGW + ACRC32B + ACRC32CB + ACRC32CH + ACRC32CW + ACRC32CX + ACRC32H + ACRC32W + ACRC32X + ACSEL + ACSELW + ACSET + ACSETM + ACSETMW + ACSETW + ACSINC + ACSINCW + ACSINV + ACSINVW + ACSNEG + ACSNEGW + ADC + ADCPS1 + ADCPS2 + ADCPS3 + ADMB + ADRPS + ADSB + AEON + AEONW + AEOR + AEORW + AERET + AEXTR + AEXTRW + AHINT + AHLT + AHVC + AIC + AISB + ALDAR + ALDARB + ALDARH + ALDARW + ALDAXP + ALDAXPW + ALDAXR + ALDAXRB + ALDAXRH + ALDAXRW + ALDP + ALDXR + ALDXRB + ALDXRH + ALDXRW + ALDXP + ALDXPW + ALSL + ALSLW + ALSR + ALSRW + AMADD + AMADDW + AMNEG + AMNEGW + AMOVK + AMOVKW + AMOVN + AMOVNW + AMOVZ + AMOVZW + AMRS + AMSR + AMSUB + AMSUBW + AMUL + AMULW + AMVN + AMVNW + ANEG + ANEGS + ANEGSW + ANEGW + ANGC + ANGCS + ANGCSW + ANGCW + AORN + AORNW + AORR + AORRW + APRFM + APRFUM + ARBIT + ARBITW + AREM + AREMW + AREV + AREV16 + AREV16W + AREV32 + AREVW + AROR + ARORW + ASBC + ASBCS + ASBCSW + ASBCW + ASBFIZ + ASBFIZW + ASBFM + ASBFMW + ASBFX + ASBFXW + ASDIV + ASDIVW + ASEV + ASEVL + ASMADDL + ASMC + ASMNEGL + ASMSUBL + ASMULH + ASMULL + ASTXR + ASTXRB + ASTXRH + ASTXP + ASTXPW + ASTXRW + ASTLP + ASTLPW + ASTLR + ASTLRB + ASTLRH + ASTLRW + ASTLXP + ASTLXPW + ASTLXR + ASTLXRB + ASTLXRH + ASTLXRW + ASTP + ASUB + ASUBS + ASUBSW + ASUBW + ASVC + ASXTB + ASXTBW + ASXTH + ASXTHW + ASXTW + ASYS + ASYSL + ATBNZ + ATBZ + ATLBI + ATST + ATSTW + AUBFIZ + AUBFIZW + AUBFM + AUBFMW + AUBFX + AUBFXW + AUDIV + AUDIVW + AUMADDL + AUMNEGL + AUMSUBL + AUMULH + AUMULL + AUREM + AUREMW + AUXTB + AUXTH + AUXTW + AUXTBW + AUXTHW + AWFE + AWFI + AYIELD + AMOVB + AMOVBU + AMOVH + AMOVHU + AMOVW + AMOVWU + AMOVD + AMOVNP + AMOVNPW + AMOVP + AMOVPD + AMOVPQ + AMOVPS + AMOVPSW + AMOVPW + ABEQ + ABNE + ABCS + ABHS + ABCC + ABLO + ABMI + ABPL + ABVS + ABVC + ABHI + ABLS + ABGE + ABLT + ABGT + ABLE + AFABSD + AFABSS + AFADDD + AFADDS + AFCCMPD + AFCCMPED + AFCCMPS + AFCCMPES + AFCMPD + AFCMPED + AFCMPES + AFCMPS + AFCVTSD + AFCVTDS + AFCVTZSD + AFCVTZSDW + AFCVTZSS + AFCVTZSSW + AFCVTZUD + AFCVTZUDW + AFCVTZUS + AFCVTZUSW + AFDIVD + AFDIVS + AFMOVD + AFMOVS + AFMULD + AFMULS + AFNEGD + AFNEGS + AFSQRTD + AFSQRTS + AFSUBD + AFSUBS + ASCVTFD + ASCVTFS + ASCVTFWD + ASCVTFWS + AUCVTFD + AUCVTFS + AUCVTFWD + AUCVTFWS + AHISTORY + ANAME + AWORD + ADYNT + AINIT + ABCASE + ACASE + ADWORD + ASIGNAME + AGOK + AEND + AFCSELS + AFCSELD + AFMAXS + AFMINS + AFMAXD + AFMIND + AFMAXNMS + AFMAXNMD + AFNMULS + AFNMULD + AFRINTNS + AFRINTND + AFRINTPS + AFRINTPD + AFRINTMS + AFRINTMD + AFRINTZS + AFRINTZD + AFRINTAS + AFRINTAD + AFRINTXS + AFRINTXD + AFRINTIS + AFRINTID + AFMADDS + AFMADDD + AFMSUBS + AFMSUBD + AFNMADDS + AFNMADDD + AFNMSUBS + AFNMSUBD + AFMINNMS + AFMINNMD + AFCVTDH + AFCVTHS + AFCVTHD + AFCVTSH + AAESD + AAESE + AAESIMC + AAESMC + ASHA1C + ASHA1H + ASHA1M + ASHA1P + ASHA1SU0 + ASHA1SU1 + ASHA256H + ASHA256H2 + ASHA256SU0 + ASHA256SU1 + ALAST + AB = obj.AJMP + ABL = obj.ACALL +) diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go new file mode 100644 index 0000000000..924e69825f --- /dev/null +++ b/src/cmd/internal/obj/arm64/anames.go @@ -0,0 +1,379 @@ +// Generated by stringer -i 7.out.go -o anames.go -p arm64 +// Do not edit. + +package arm64 + +import "cmd/internal/obj" + +var Anames = []string{ + obj.A_ARCHSPECIFIC: "ADC", + "ADCS", + "ADCSW", + "ADCW", + "ADD", + "ADDS", + "ADDSW", + "ADDW", + "ADR", + "ADRP", + "AND", + "ANDS", + "ANDSW", + "ANDW", + "ASR", + "ASRW", + "AT", + "BFI", + "BFIW", + "BFM", + "BFMW", + "BFXIL", + "BFXILW", + "BIC", + "BICS", + "BICSW", + "BICW", + "BRK", + "CBNZ", + "CBNZW", + "CBZ", + "CBZW", + "CCMN", + "CCMNW", + "CCMP", + "CCMPW", + "CINC", + "CINCW", + "CINV", + "CINVW", + "CLREX", + "CLS", + "CLSW", + "CLZ", + "CLZW", + "CMN", + "CMNW", + "CMP", + "CMPW", + "CNEG", + "CNEGW", + "CRC32B", + "CRC32CB", + "CRC32CH", + "CRC32CW", + "CRC32CX", + "CRC32H", + "CRC32W", + "CRC32X", + "CSEL", + "CSELW", + "CSET", + "CSETM", + "CSETMW", + "CSETW", + "CSINC", + "CSINCW", + "CSINV", + "CSINVW", + "CSNEG", + "CSNEGW", + "DC", + "DCPS1", + "DCPS2", + "DCPS3", + "DMB", + "DRPS", + "DSB", + "EON", + "EONW", + "EOR", + "EORW", + "ERET", + "EXTR", + "EXTRW", + "HINT", + "HLT", + "HVC", + "IC", + "ISB", + "LDAR", + "LDARB", + "LDARH", + "LDARW", + "LDAXP", + "LDAXPW", + "LDAXR", + "LDAXRB", + "LDAXRH", + "LDAXRW", + "LDP", + "LDXR", + "LDXRB", + "LDXRH", + "LDXRW", + "LDXP", + "LDXPW", + "LSL", + "LSLW", + "LSR", + "LSRW", + "MADD", + "MADDW", + "MNEG", + "MNEGW", + "MOVK", + "MOVKW", + "MOVN", + "MOVNW", + "MOVZ", + "MOVZW", + "MRS", + "MSR", + "MSUB", + "MSUBW", + "MUL", + "MULW", + "MVN", + "MVNW", + "NEG", + "NEGS", + "NEGSW", + "NEGW", + "NGC", + "NGCS", + "NGCSW", + "NGCW", + "ORN", + "ORNW", + "ORR", + "ORRW", + "PRFM", + "PRFUM", + "RBIT", + "RBITW", + "REM", + "REMW", + "REV", + "REV16", + "REV16W", + "REV32", + "REVW", + "ROR", + "RORW", + "SBC", + "SBCS", + "SBCSW", + "SBCW", + "SBFIZ", + "SBFIZW", + "SBFM", + "SBFMW", + "SBFX", + "SBFXW", + "SDIV", + "SDIVW", + "SEV", + "SEVL", + "SMADDL", + "SMC", + "SMNEGL", + "SMSUBL", + "SMULH", + "SMULL", + "STXR", + "STXRB", + "STXRH", + "STXP", + "STXPW", + "STXRW", + "STLP", + "STLPW", + "STLR", + "STLRB", + "STLRH", + "STLRW", + "STLXP", + "STLXPW", + "STLXR", + "STLXRB", + "STLXRH", + "STLXRW", + "STP", + "SUB", + "SUBS", + "SUBSW", + "SUBW", + "SVC", + "SXTB", + "SXTBW", + "SXTH", + "SXTHW", + "SXTW", + "SYS", + "SYSL", + "TBNZ", + "TBZ", + "TLBI", + "TST", + "TSTW", + "UBFIZ", + "UBFIZW", + "UBFM", + "UBFMW", + "UBFX", + "UBFXW", + "UDIV", + "UDIVW", + "UMADDL", + "UMNEGL", + "UMSUBL", + "UMULH", + "UMULL", + "UREM", + "UREMW", + "UXTB", + "UXTH", + "UXTW", + "UXTBW", + "UXTHW", + "WFE", + "WFI", + "YIELD", + "MOVB", + "MOVBU", + "MOVH", + "MOVHU", + "MOVW", + "MOVWU", + "MOVD", + "MOVNP", + "MOVNPW", + "MOVP", + "MOVPD", + "MOVPQ", + "MOVPS", + "MOVPSW", + "MOVPW", + "BEQ", + "BNE", + "BCS", + "BHS", + "BCC", + "BLO", + "BMI", + "BPL", + "BVS", + "BVC", + "BHI", + "BLS", + "BGE", + "BLT", + "BGT", + "BLE", + "FABSD", + "FABSS", + "FADDD", + "FADDS", + "FCCMPD", + "FCCMPED", + "FCCMPS", + "FCCMPES", + "FCMPD", + "FCMPED", + "FCMPES", + "FCMPS", + "FCVTSD", + "FCVTDS", + "FCVTZSD", + "FCVTZSDW", + "FCVTZSS", + "FCVTZSSW", + "FCVTZUD", + "FCVTZUDW", + "FCVTZUS", + "FCVTZUSW", + "FDIVD", + "FDIVS", + "FMOVD", + "FMOVS", + "FMULD", + "FMULS", + "FNEGD", + "FNEGS", + "FSQRTD", + "FSQRTS", + "FSUBD", + "FSUBS", + "SCVTFD", + "SCVTFS", + "SCVTFWD", + "SCVTFWS", + "UCVTFD", + "UCVTFS", + "UCVTFWD", + "UCVTFWS", + "HISTORY", + "NAME", + "WORD", + "DYNT", + "INIT", + "BCASE", + "CASE", + "DWORD", + "SIGNAME", + "GOK", + "END", + "FCSELS", + "FCSELD", + "FMAXS", + "FMINS", + "FMAXD", + "FMIND", + "FMAXNMS", + "FMAXNMD", + "FNMULS", + "FNMULD", + "FRINTNS", + "FRINTND", + "FRINTPS", + "FRINTPD", + "FRINTMS", + "FRINTMD", + "FRINTZS", + "FRINTZD", + "FRINTAS", + "FRINTAD", + "FRINTXS", + "FRINTXD", + "FRINTIS", + "FRINTID", + "FMADDS", + "FMADDD", + "FMSUBS", + "FMSUBD", + "FNMADDS", + "FNMADDD", + "FNMSUBS", + "FNMSUBD", + "FMINNMS", + "FMINNMD", + "FCVTDH", + "FCVTHS", + "FCVTHD", + "FCVTSH", + "AESD", + "AESE", + "AESIMC", + "AESMC", + "SHA1C", + "SHA1H", + "SHA1M", + "SHA1P", + "SHA1SU0", + "SHA1SU1", + "SHA256H", + "SHA256H2", + "SHA256SU0", + "SHA256SU1", + "LAST", +} diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go new file mode 100644 index 0000000000..3ff429f413 --- /dev/null +++ b/src/cmd/internal/obj/arm64/anames7.go @@ -0,0 +1,62 @@ +package arm64 + +var cnames7 = []string{ + "NONE", + "REG", + "RSP", + "FREG", + "VREG", + "PAIR", + "SHIFT", + "EXTREG", + "SPR", + "COND", + "ZCON", + "ADDCON0", + "ADDCON", + "MOVCON", + "BITCON", + "ABCON", + "MBCON", + "LCON", + "VCON", + "FCON", + "VCONADDR", + "AACON", + "LACON", + "AECON", + "SBRA", + "LBRA", + "NPAUTO", + "NSAUTO", + "PSAUTO", + "PPAUTO", + "UAUTO4K", + "UAUTO8K", + "UAUTO16K", + "UAUTO32K", + "UAUTO64K", + "LAUTO", + "SEXT1", + "SEXT2", + "SEXT4", + "SEXT8", + "SEXT16", + "LEXT", + "ZOREG", + "NPOREG", + "NSOREG", + "PSOREG", + "PPOREG", + "UOREG4K", + "UOREG8K", + "UOREG16K", + "UOREG32K", + "UOREG64K", + "LOREG", + "ADDR", + "ROFF", + "GOK", + "TEXTSIZE", + "NCLASS", +} diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go new file mode 100644 index 0000000000..ba56f82df0 --- /dev/null +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -0,0 +1,4194 @@ +// cmd/7l/asm.c, cmd/7l/asmout.c, cmd/7l/optab.c, cmd/7l/span.c, cmd/ld/sub.c, cmd/ld/mod.c, from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/ +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import ( + "cmd/internal/obj" + "fmt" + "log" + "math" + "sort" +) + +const ( + FuncAlign = 16 +) + +const ( + REGFROM = 1 +) + +type Optab struct { + as uint16 + a1 uint8 + a2 uint8 + a3 uint8 + type_ int8 + size int8 + param int16 + flag int8 + scond uint16 +} + +type Oprange struct { + start []Optab + stop []Optab +} + +var oprange [ALAST]Oprange + +var xcmp [C_NCLASS][C_NCLASS]uint8 + +const ( + S32 = 0 << 31 + S64 = 1 << 31 + Sbit = 1 << 29 + LSL0_32 = 2 << 13 + LSL0_64 = 3 << 13 +) + +func OPDP2(x uint32) uint32 { + return 0<<30 | 0<<29 | 0xd6<<21 | x<<10 +} + +func OPDP3(sf uint32, op54 uint32, op31 uint32, o0 uint32) uint32 { + return sf<<31 | op54<<29 | 0x1B<<24 | op31<<21 | o0<<15 +} + +func OPBcc(x uint32) uint32 { + return 0x2A<<25 | 0<<24 | 0<<4 | x&15 +} + +func OPBLR(x uint32) uint32 { + /* x=0, JMP; 1, CALL; 2, RET */ + return 0x6B<<25 | 0<<23 | x<<21 | 0x1F<<16 | 0<<10 +} + +func SYSOP(l uint32, op0 uint32, op1 uint32, crn uint32, crm uint32, op2 uint32, rt uint32) uint32 { + return 0x354<<22 | l<<21 | op0<<19 | op1<<16 | crn&15<<12 | crm&15<<8 | op2<<5 | rt +} + +func SYSHINT(x uint32) uint32 { + return SYSOP(0, 0, 3, 2, 0, x, 0x1F) +} + +func LDSTR12U(sz uint32, v uint32, opc uint32) uint32 { + return sz<<30 | 7<<27 | v<<26 | 1<<24 | opc<<22 +} + +func LDSTR9S(sz uint32, v uint32, opc uint32) uint32 { + return sz<<30 | 7<<27 | v<<26 | 0<<24 | opc<<22 +} + +func LD2STR(o uint32) uint32 { + return o &^ (3 << 22) +} + +func LDSTX(sz uint32, o2 uint32, l uint32, o1 uint32, o0 uint32) uint32 { + return sz<<30 | 0x8<<24 | o2<<23 | l<<22 | o1<<21 | o0<<15 +} + +func FPCMP(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<14 | 8<<10 | op2 +} + +func FPCCMP(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | 1<<10 | op<<4 +} + +func FPOP1S(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<15 | 0x10<<10 +} + +func FPOP2S(m uint32, s uint32, type_ uint32, op uint32) uint32 { + return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<12 | 2<<10 +} + +func FPCVTI(sf uint32, s uint32, type_ uint32, rmode uint32, op uint32) uint32 { + return sf<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | rmode<<19 | op<<16 | 0<<10 +} + +func ADR(p uint32, o uint32, rt uint32) uint32 { + return p<<31 | (o&3)<<29 | 0x10<<24 | ((o>>2)&0x7FFFF)<<5 | rt&31 +} + +func OPBIT(x uint32) uint32 { + return 1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | x<<10 +} + +const ( + LFROM = 1 << 0 + LTO = 1 << 1 + LPOOL = 1 << 2 +) + +var optab = []Optab{ + /* struct Optab: + OPCODE, from, prog->reg, to, type,size,param,flag,scond */ + {obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0}, + + /* arithmetic operations */ + {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {AADC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AADC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ANEG, C_REG, C_NONE, C_REG, 25, 4, 0, 0, 0}, + {ANGC, C_REG, C_NONE, C_REG, 17, 4, 0, 0, 0}, + {ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0}, + {AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0, 0, 0}, + {AADD, C_ADDCON, C_NONE, C_RSP, 2, 4, 0, 0, 0}, + {ACMP, C_ADDCON, C_RSP, C_NONE, 2, 4, 0, 0, 0}, + // TODO: these don't work properly. + // {AADD, C_MBCON, C_RSP, C_RSP, 2, 4, 0, 0, 0}, + // {AADD, C_MBCON, C_NONE, C_RSP, 2, 4, 0, 0, 0}, + // {ACMP, C_MBCON, C_RSP, C_NONE, 2, 4, 0, 0, 0}, + {AADD, C_VCON, C_RSP, C_RSP, 13, 8, 0, LFROM, 0}, + {AADD, C_VCON, C_NONE, C_RSP, 13, 8, 0, LFROM, 0}, + {ACMP, C_VCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0}, + {AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0}, + {AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0}, + {ANEG, C_SHIFT, C_NONE, C_REG, 26, 4, 0, 0, 0}, + {AADD, C_REG, C_RSP, C_RSP, 27, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {ACMP, C_REG, C_RSP, C_NONE, 27, 4, 0, 0, 0}, + {AADD, C_EXTREG, C_RSP, C_RSP, 27, 4, 0, 0, 0}, + {AADD, C_EXTREG, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {AMVN, C_EXTREG, C_NONE, C_RSP, 27, 4, 0, 0, 0}, + {ACMP, C_EXTREG, C_RSP, C_NONE, 27, 4, 0, 0, 0}, + {AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + + /* logical operations */ + {AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ABIC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {ABIC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + // TODO: these don't work properly. + // {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0}, + // {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0}, + // {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0}, + // {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0}, + {AAND, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0}, + {AAND, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, + {ABIC, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0}, + {ABIC, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0}, + {AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0}, + {AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {ABIC, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0}, + {ABIC, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0}, + {AMOVD, C_RSP, C_NONE, C_RSP, 24, 4, 0, 0, 0}, + {AMVN, C_REG, C_NONE, C_REG, 24, 4, 0, 0, 0}, + {AMOVB, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVHU */ + {AMOVW, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVWU */ + /* TODO: MVN C_SHIFT */ + + /* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */ + {AMOVW, C_MOVCON, C_NONE, C_REG, 32, 4, 0, 0, 0}, + {AMOVD, C_MOVCON, C_NONE, C_REG, 32, 4, 0, 0, 0}, + + // TODO: these don't work properly. + // { AMOVW, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0}, + // { AMOVD, C_ADDCON, C_NONE, C_REG, 2, 4, 0 , 0}, + // { AMOVW, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0}, + // { AMOVD, C_BITCON, C_NONE, C_REG, 53, 4, 0 , 0}, + + {AMOVK, C_VCON, C_NONE, C_REG, 33, 4, 0, 0, 0}, + {AMOVD, C_AACON, C_NONE, C_REG, 4, 4, REGFROM, 0, 0}, + {ASDIV, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0}, + {ASDIV, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0}, + {AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, + {AB, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0}, + {ABL, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {obj.ARET, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0}, + {obj.ARET, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0}, + {AADRP, C_SBRA, C_NONE, C_REG, 60, 4, 0, 0, 0}, + {AADR, C_SBRA, C_NONE, C_REG, 61, 4, 0, 0, 0}, + {ABFM, C_VCON, C_REG, C_REG, 42, 4, 0, 0, 0}, + {ABFI, C_VCON, C_REG, C_REG, 43, 4, 0, 0, 0}, + {AEXTR, C_VCON, C_REG, C_REG, 44, 4, 0, 0, 0}, + {ASXTB, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, + {ACLS, C_REG, C_NONE, C_REG, 46, 4, 0, 0, 0}, + {ABEQ, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0}, + {ALSL, C_VCON, C_REG, C_REG, 8, 4, 0, 0, 0}, + {ALSL, C_VCON, C_NONE, C_REG, 8, 4, 0, 0, 0}, + {ALSL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0}, + {ALSL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0}, + {ASVC, C_NONE, C_NONE, C_VCON, 10, 4, 0, 0, 0}, + {ASVC, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0}, + {ADWORD, C_NONE, C_NONE, C_VCON, 11, 8, 0, 0, 0}, + {ADWORD, C_NONE, C_NONE, C_LEXT, 11, 8, 0, 0, 0}, + {ADWORD, C_NONE, C_NONE, C_ADDR, 11, 8, 0, 0, 0}, + {ADWORD, C_NONE, C_NONE, C_LACON, 11, 8, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0}, + {AWORD, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0}, + {AMOVW, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0}, + {AMOVD, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0}, + {AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AMOVH, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AMOVD, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AMOVB, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0}, + {AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0}, + {AMOVH, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0}, + {AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0}, + {AMOVD, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0}, + {AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0}, + {AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0}, + {AMADD, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0}, + {AREM, C_REG, C_REG, C_REG, 16, 8, 0, 0, 0}, + {AREM, C_REG, C_NONE, C_REG, 16, 8, 0, 0, 0}, + {ACSEL, C_COND, C_REG, C_REG, 18, 4, 0, 0, 0}, /* from3 optional */ + {ACSET, C_COND, C_NONE, C_REG, 18, 4, 0, 0, 0}, + {ACCMN, C_COND, C_REG, C_VCON, 19, 4, 0, 0, 0}, /* from3 either C_REG or C_VCON */ + + /* scaled 12-bit unsigned displacement store */ + {AMOVB, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0}, + + {AMOVH, C_REG, C_NONE, C_UAUTO8K, 20, 4, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_UOREG8K, 20, 4, 0, 0, 0}, + + {AMOVW, C_REG, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0}, + + /* unscaled 9-bit signed displacement store */ + {AMOVB, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + + {AMOVH, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + + {AMOVD, C_REG, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0}, + {AMOVD, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + + /* short displacement load */ + {AMOVB, C_UAUTO4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVB, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVB, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVB, C_UOREG4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVB, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + + {AMOVBU, C_UAUTO4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVBU, C_UOREG4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVBU, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + + {AMOVH, C_UAUTO8K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVH, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVH, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVH, C_UOREG8K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVH, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + + {AMOVW, C_UAUTO16K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVW, C_UOREG16K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVW, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + + {AMOVD, C_UAUTO32K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVD, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVD, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0}, + {AMOVD, C_UOREG32K, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + {AMOVD, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0}, + + /* long displacement store */ + {AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0}, + {AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0}, + {AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0}, + {AMOVH, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0}, + {AMOVH, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0}, + {AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0}, + {AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0}, + {AMOVD, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0}, + + /* long displacement load */ + {AMOVB, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0}, + {AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVH, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0}, + {AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0}, + {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVD, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0}, + {AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + {AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0}, + + /* load long effective stack address (load int32 offset and add) */ + {AMOVD, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0}, + + /* pre/post-indexed load (unscaled, signed 9-bit offset) */ + {AMOVD, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVW, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVH, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVB, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST}, + {AFMOVS, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST}, + {AFMOVD, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST}, + {AMOVD, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVW, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVH, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVB, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AMOVBU, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE}, + {AFMOVS, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE}, + {AFMOVD, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE}, + + /* pre/post-indexed store (unscaled, signed 9-bit offset) */ + {AMOVD, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVW, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVH, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVB, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVBU, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AFMOVS, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AFMOVD, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST}, + {AMOVD, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVW, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVH, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVB, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AMOVBU, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AFMOVS, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + {AFMOVD, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE}, + + /* pre/post-indexed load/store register pair + (unscaled, signed 10-bit quad-aligned offset) */ + {ALDP, C_LOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE}, + {ALDP, C_LOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST}, + {ASTP, C_PAIR, C_NONE, C_LOREG, 67, 4, 0, 0, C_XPRE}, + {ASTP, C_PAIR, C_NONE, C_LOREG, 67, 4, 0, 0, C_XPOST}, + + /* special */ + {AMOVD, C_SPR, C_NONE, C_REG, 35, 4, 0, 0, 0}, + {AMRS, C_SPR, C_NONE, C_REG, 35, 4, 0, 0, 0}, + {AMOVD, C_REG, C_NONE, C_SPR, 36, 4, 0, 0, 0}, + {AMSR, C_REG, C_NONE, C_SPR, 36, 4, 0, 0, 0}, + {AMOVD, C_VCON, C_NONE, C_SPR, 37, 4, 0, 0, 0}, + {AMSR, C_VCON, C_NONE, C_SPR, 37, 4, 0, 0, 0}, + {AERET, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0}, + {AFMOVS, C_UAUTO16K, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVS, C_NSAUTO, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVS, C_ZOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVS, C_UOREG16K, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVS, C_NSOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVD, C_UAUTO32K, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVD, C_NSAUTO, C_NONE, C_FREG, 21, 4, REGSP, 0, 0}, + {AFMOVD, C_ZOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVD, C_UOREG32K, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVD, C_NSOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AFMOVS, C_FREG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AFMOVD, C_FREG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0}, + {AFMOVD, C_FREG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0}, + {AFMOVS, C_LAUTO, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0}, + {AFMOVS, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0}, + {AFMOVD, C_LAUTO, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0}, + {AFMOVD, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0}, + {AFMOVS, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0}, + {AFMOVD, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0}, + {AFMOVD, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0}, + {AFADDS, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFADDS, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0}, + {AFADDS, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFADDS, C_FCON, C_FREG, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVS, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVD, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFCVTZSD, C_FREG, C_NONE, C_REG, 29, 4, 0, 0, 0}, + {ASCVTFD, C_REG, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {AFCMPS, C_FREG, C_FREG, C_NONE, 56, 4, 0, 0, 0}, + {AFCMPS, C_FCON, C_FREG, C_NONE, 56, 4, 0, 0, 0}, + {AFCCMPS, C_COND, C_REG, C_VCON, 57, 4, 0, 0, 0}, + {AFCSELD, C_COND, C_REG, C_FREG, 18, 4, 0, 0, 0}, + {AFCVTSD, C_FREG, C_NONE, C_FREG, 29, 4, 0, 0, 0}, + {ACASE, C_REG, C_NONE, C_REG, 62, 4 * 4, 0, 0, 0}, + {ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, 0, 0}, + {ACLREX, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0}, + {ACLREX, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0}, + {ACBZ, C_REG, C_NONE, C_SBRA, 39, 4, 0, 0, 0}, + {ATBZ, C_VCON, C_REG, C_SBRA, 40, 4, 0, 0, 0}, + {ASYS, C_VCON, C_NONE, C_NONE, 50, 4, 0, 0, 0}, + {ASYS, C_VCON, C_REG, C_NONE, 50, 4, 0, 0, 0}, + {ASYSL, C_VCON, C_NONE, C_REG, 50, 4, 0, 0, 0}, + {ADMB, C_VCON, C_NONE, C_NONE, 51, 4, 0, 0, 0}, + {AHINT, C_VCON, C_NONE, C_NONE, 52, 4, 0, 0, 0}, + {ALDAR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDXR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDAXR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0}, + {ALDXP, C_ZOREG, C_REG, C_REG, 58, 4, 0, 0, 0}, + {ASTLR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // to3=C_NONE + {ASTXR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // to3=C_REG + {ASTLXR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // to3=C_REG + + // { ASTXP, C_REG, C_NONE, C_ZOREG, 59, 4, 0 , 0}, // TODO(aram): + + {AAESD, C_VREG, C_NONE, C_VREG, 29, 4, 0, 0, 0}, + {ASHA1C, C_VREG, C_REG, C_VREG, 1, 4, 0, 0, 0}, + + {obj.AUNDEF, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0}, + {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.APCDATA, C_VCON, C_NONE, C_VCON, 0, 0, 0, 0, 0}, + {obj.AFUNCDATA, C_VCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0}, + {obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, + {obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL + {obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL + + {obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0}, +} + +/* + * valid pstate field values, and value to use in instruction + */ +var pstatefield = []struct { + a uint32 + b uint32 +}{ + {REG_SPSel, 0<<16 | 4<<12 | 5<<5}, + {REG_DAIFSet, 3<<16 | 4<<12 | 6<<5}, + {REG_DAIFClr, 3<<16 | 4<<12 | 7<<5}, +} + +var pool struct { + start uint32 + size uint32 +} + +func prasm(p *obj.Prog) { + fmt.Printf("%v\n", p) +} + +func span7(ctxt *obj.Link, cursym *obj.LSym) { + p := cursym.Text + if p == nil || p.Link == nil { // handle external functions and ELF section symbols + return + } + ctxt.Cursym = cursym + ctxt.Autosize = int32(p.To.Offset&0xffffffff) + 8 + + if oprange[AAND].start == nil { + buildop(ctxt) + } + + bflag := 0 + c := int32(0) + p.Pc = int64(c) + var m int + var o *Optab + for p = p.Link; p != nil; p = p.Link { + ctxt.Curp = p + if p.As == ADWORD && (c&7) != 0 { + c += 4 + } + p.Pc = int64(c) + o = oplook(ctxt, p) + m = int(o.size) + if m == 0 { + if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA { + ctxt.Diag("zero-width instruction\n%v", p) + } + continue + } + + switch o.flag & (LFROM | LTO) { + case LFROM: + addpool(ctxt, p, &p.From) + + case LTO: + addpool(ctxt, p, &p.To) + break + } + + if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */ + checkpool(ctxt, p, 0) + } + c += int32(m) + if ctxt.Blitrl != nil { + checkpool(ctxt, p, 1) + } + } + + cursym.Size = int64(c) + + /* + * if any procedure is large enough to + * generate a large SBRA branch, then + * generate extra passes putting branches + * around jmps to fix. this is rare. + */ + for bflag != 0 { + bflag = 0 + c = 0 + for p = cursym.Text; p != nil; p = p.Link { + if p.As == ADWORD && (c&7) != 0 { + c += 4 + } + p.Pc = int64(c) + o = oplook(ctxt, p) + + /* very large branches + if(o->type == 6 && p->cond) { + otxt = p->cond->pc - c; + if(otxt < 0) + otxt = -otxt; + if(otxt >= (1L<<17) - 10) { + q = ctxt->arch->prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = obj.TYPE_BRANCH; + q->cond = p->cond; + p->cond = q; + q = ctxt->arch->prg(); + q->link = p->link; + p->link = q; + q->as = AB; + q->to.type = obj.TYPE_BRANCH; + q->cond = q->link->link; + bflag = 1; + } + } + */ + m = int(o.size) + + if m == 0 { + if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA { + ctxt.Diag("zero-width instruction\n%v", p) + } + continue + } + + c += int32(m) + } + } + + c += -c & (FuncAlign - 1) + cursym.Size = int64(c) + + /* + * lay out the code, emitting code and data relocations. + */ + if ctxt.Tlsg == nil { + ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0) + } + obj.Symgrow(ctxt, cursym, cursym.Size) + bp := cursym.P + psz := int32(0) + var i int + var out [6]uint32 + for p := cursym.Text.Link; p != nil; p = p.Link { + ctxt.Pc = p.Pc + ctxt.Curp = p + o = oplook(ctxt, p) + + // need to align DWORDs on 8-byte boundary. The ISA doesn't + // require it, but the various 64-bit loads we generate assume it. + if o.as == ADWORD && psz%8 != 0 { + bp[3] = 0 + bp[2] = bp[3] + bp[1] = bp[2] + bp[0] = bp[1] + bp = bp[4:] + psz += 4 + } + + if int(o.size) > 4*len(out) { + log.Fatalf("out array in span7 is too small, need at least %d for %v", o.size/4, p) + } + asmout(ctxt, p, o, out[:]) + for i = 0; i < int(o.size/4); i++ { + ctxt.Arch.ByteOrder.PutUint32(bp, out[i]) + bp = bp[4:] + psz += 4 + } + } +} + +/* + * when the first reference to the literal pool threatens + * to go out of range of a 1Mb PC-relative offset + * drop the pool now, and branch round it. + */ +func checkpool(ctxt *obj.Link, p *obj.Prog, skip int) { + if pool.size >= 0xffff0 || !(ispcdisp(int32(p.Pc+4+int64(pool.size)-int64(pool.start)+8)) != 0) { + flushpool(ctxt, p, skip) + } else if p.Link == nil { + flushpool(ctxt, p, 2) + } +} + +func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) { + if ctxt.Blitrl != nil { + if skip != 0 { + if ctxt.Debugvlog != 0 && skip == 1 { + fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start) + } + q := ctxt.NewProg() + q.As = AB + q.To.Type = obj.TYPE_BRANCH + q.Pcond = p.Link + q.Link = ctxt.Blitrl + q.Lineno = p.Lineno + ctxt.Blitrl = q + } else if p.Pc+int64(pool.size)-int64(pool.start) < 1024*1024 { + return + } + ctxt.Elitrl.Link = p.Link + p.Link = ctxt.Blitrl + + // BUG(minux): how to correctly handle line number for constant pool entries? + // for now, we set line number to the last instruction preceding them at least + // this won't bloat the .debug_line tables + for ctxt.Blitrl != nil { + ctxt.Blitrl.Lineno = p.Lineno + ctxt.Blitrl = ctxt.Blitrl.Link + } + + ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */ + ctxt.Elitrl = nil + pool.size = 0 + pool.start = 0 + } +} + +/* + * TODO: hash + */ +func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) { + c := aclass(ctxt, a) + t := *ctxt.NewProg() + t.As = AWORD + sz := 4 + + // MOVW foo(SB), R is actually + // MOV addr, REGTEMP + // MOVW REGTEMP, R + // where addr is the address of the DWORD containing the address of foo. + if p.As == AMOVD || c == C_ADDR || c == C_VCON { + t.As = ADWORD + sz = 8 + } + + switch c { + // TODO(aram): remove. + default: + if a.Name != obj.NAME_EXTERN { + fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(c), p) + } + + t.To.Offset = a.Offset + t.To.Sym = a.Sym + t.To.Type = a.Type + t.To.Name = a.Name + + /* This is here to work around a bug where we generate negative + operands that match C_MOVCON, but we use them with + instructions that only accept unsigned immediates. This + will cause oplook to return a variant of the instruction + that loads the negative constant from memory, rather than + using the immediate form. Because of that load, we get here, + so we need to know what to do with C_MOVCON. + + The correct fix is to use the "negation" instruction variant, + e.g. CMN $1, R instead of CMP $-1, R, or SUB $1, R instead + of ADD $-1, R. */ + case C_MOVCON, + + /* This is here because MOV uint12<<12, R is disabled in optab. + Because of this, we need to load the constant from memory. */ + C_ADDCON, + + /* These are here because they are disabled in optab. + Because of this, we need to load the constant from memory. */ + C_BITCON, + C_ABCON, + C_MBCON, + C_PSAUTO, + C_PPAUTO, + C_UAUTO4K, + C_UAUTO8K, + C_UAUTO16K, + C_UAUTO32K, + C_UAUTO64K, + C_NSAUTO, + C_NPAUTO, + C_LAUTO, + C_PPOREG, + C_PSOREG, + C_UOREG4K, + C_UOREG8K, + C_UOREG16K, + C_UOREG32K, + C_UOREG64K, + C_NSOREG, + C_NPOREG, + C_LOREG, + C_LACON, + C_LCON, + C_VCON: + if a.Name == obj.NAME_EXTERN { + fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(c), p) + } + + t.To.Type = obj.TYPE_CONST + t.To.Offset = ctxt.Instoffset + break + } + + for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */ + if q.To == t.To { + p.Pcond = q + return + } + } + + q := ctxt.NewProg() + *q = t + q.Pc = int64(pool.size) + if ctxt.Blitrl == nil { + ctxt.Blitrl = q + pool.start = uint32(p.Pc) + } else { + ctxt.Elitrl.Link = q + } + ctxt.Elitrl = q + pool.size = -pool.size & (FuncAlign - 1) + pool.size += uint32(sz) + p.Pcond = q +} + +func regoff(ctxt *obj.Link, a *obj.Addr) uint32 { + ctxt.Instoffset = 0 + aclass(ctxt, a) + return uint32(ctxt.Instoffset) +} + +func ispcdisp(v int32) int { + /* pc-relative addressing will reach? */ + return bool2int(v >= -0xfffff && v <= 0xfffff && (v&3) == 0) +} + +func isaddcon(v int64) int { + /* uimm12 or uimm24? */ + if v < 0 { + return 0 + } + if (v & 0xFFF) == 0 { + v >>= 12 + } + return bool2int(v <= 0xFFF) +} + +func isbitcon(v uint64) int { + /* fancy bimm32 or bimm64? */ + // TODO(aram): + return 0 + // return bool2int(findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil) +} + +func autoclass(l int64) int { + if l < 0 { + if l >= -256 { + return C_NSAUTO + } + if l >= -512 && (l&7) == 0 { + return C_NPAUTO + } + return C_LAUTO + } + + if l <= 255 { + return C_PSAUTO + } + if l <= 504 && (l&7) == 0 { + return C_PPAUTO + } + if l <= 4095 { + return C_UAUTO4K + } + if l <= 8190 && (l&1) == 0 { + return C_UAUTO8K + } + if l <= 16380 && (l&3) == 0 { + return C_UAUTO16K + } + if l <= 32760 && (l&7) == 0 { + return C_UAUTO32K + } + if l <= 65520 && (l&0xF) == 0 { + return C_UAUTO64K + } + return C_LAUTO +} + +func oregclass(l int64) int { + if l == 0 { + return C_ZOREG + } + return autoclass(l) - C_NPAUTO + C_NPOREG +} + +/* + * given an offset v and a class c (see above) + * return the offset value to use in the instruction, + * scaled if necessary + */ +func offsetshift(ctxt *obj.Link, v int64, c int) int64 { + s := 0 + if c >= C_SEXT1 && c <= C_SEXT16 { + s = c - C_SEXT1 + } else if c >= C_UAUTO4K && c <= C_UAUTO64K { + s = c - C_UAUTO4K + } else if c >= C_UOREG4K && c <= C_UOREG64K { + s = c - C_UOREG4K + } + vs := v >> uint(s) + if vs<= REG_SPECIAL: + return C_SPR + } + return C_GOK +} + +func aclass(ctxt *obj.Link, a *obj.Addr) int { + switch a.Type { + case obj.TYPE_NONE: + return C_NONE + + case obj.TYPE_REG: + return rclass(a.Reg) + + case obj.TYPE_REGREG: + return C_PAIR + + case obj.TYPE_SHIFT: + return C_SHIFT + + case obj.TYPE_MEM: + switch a.Name { + case obj.NAME_EXTERN, + obj.NAME_STATIC: + if a.Sym == nil { + break + } + ctxt.Instoffset = a.Offset + if a.Sym != nil { // use relocation + return C_ADDR + } + return C_LEXT + + case obj.NAME_AUTO: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + return autoclass(ctxt.Instoffset) + + case obj.NAME_PARAM: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8 + return autoclass(ctxt.Instoffset) + + case obj.TYPE_NONE: + ctxt.Instoffset = a.Offset + return oregclass(ctxt.Instoffset) + } + return C_GOK + + case obj.TYPE_FCONST: + return C_FCON + + case obj.TYPE_TEXTSIZE: + return C_TEXTSIZE + + case obj.TYPE_CONST, + obj.TYPE_ADDR: + switch a.Name { + case obj.TYPE_NONE: + ctxt.Instoffset = a.Offset + if a.Reg != 0 && a.Reg != REGZERO { + goto aconsize + } + v := ctxt.Instoffset + if v == 0 { + return C_ZCON + } + if isaddcon(v) != 0 { + if v <= 0xFFF { + return C_ADDCON0 + } + if isbitcon(uint64(v)) != 0 { + return C_ABCON + } + return C_ADDCON + } + + t := movcon(v) + if t >= 0 { + if isbitcon(uint64(v)) != 0 { + return C_MBCON + } + return C_MOVCON + } + + t = movcon(^v) + if t >= 0 { + if isbitcon(uint64(v)) != 0 { + return C_MBCON + } + return C_MOVCON + } + + if isbitcon(uint64(v)) != 0 { + return C_BITCON + } + + if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) { + return C_LCON + } + return C_VCON + + case obj.NAME_EXTERN, + obj.NAME_STATIC: + s := a.Sym + if s == nil { + break + } + ctxt.Instoffset = a.Offset + return C_VCONADDR + + case obj.NAME_AUTO: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + goto aconsize + + case obj.NAME_PARAM: + ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8 + goto aconsize + } + return C_GOK + + aconsize: + if isaddcon(ctxt.Instoffset) != 0 { + return C_AACON + } + return C_LACON + + case obj.TYPE_BRANCH: + return C_SBRA + } + + return C_GOK +} + +func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { + a1 := int(p.Optab) + if a1 != 0 { + return &optab[a1-1:][0] + } + a1 = int(p.From.Class) + if a1 == 0 { + a1 = aclass(ctxt, &p.From) + 1 + p.From.Class = int8(a1) + } + + a1-- + a3 := int(p.To.Class) + if a3 == 0 { + a3 = aclass(ctxt, &p.To) + 1 + p.To.Class = int8(a3) + } + + a3-- + a2 := C_NONE + if p.Reg != 0 { + a2 = rclass(p.Reg) + } + r := int(p.As) + o := oprange[r].start + if o == nil { + o = oprange[r].stop /* just generate an error */ + } + + if false { + fmt.Printf("oplook %v %d %d %d\n", obj.Aconv(int(p.As)), a1, a2, a3) + fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type) + } + + e := oprange[r].stop + c1 := xcmp[a1][:] + c2 := xcmp[a2][:] + c3 := xcmp[a3][:] + c4 := xcmp[p.Scond>>5][:] + for ; -cap(o) < -cap(e); o = o[1:] { + if int(o[0].a2) == a2 || c2[o[0].a2] != 0 { + if c4[o[0].scond>>5] != 0 { + if c1[o[0].a1] != 0 { + if c3[o[0].a3] != 0 { + p.Optab = uint16((-cap(o) + cap(optab)) + 1) + return &o[0] + } + } + } + } + } + + ctxt.Diag("illegal combination %v %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type) + prasm(p) + if o == nil { + o = optab + } + return &o[0] +} + +func cmp(a int, b int) bool { + if a == b { + return true + } + switch a { + case C_RSP: + if b == C_REG { + return true + } + + case C_REG: + if b == C_ZCON { + return true + } + + case C_ADDCON0: + if b == C_ZCON { + return true + } + + case C_ADDCON: + if b == C_ZCON || b == C_ADDCON0 || b == C_ABCON { + return true + } + + case C_BITCON: + if b == C_ABCON || b == C_MBCON { + return true + } + + case C_MOVCON: + if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 { + return true + } + + case C_LCON: + if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_MBCON || b == C_MOVCON { + return true + } + + case C_VCON: + if b == C_VCONADDR { + return true + } else { + return cmp(C_LCON, b) + } + fallthrough + + case C_LACON: + if b == C_AACON { + return true + } + + case C_SEXT2: + if b == C_SEXT1 { + return true + } + + case C_SEXT4: + if b == C_SEXT1 || b == C_SEXT2 { + return true + } + + case C_SEXT8: + if b >= C_SEXT1 && b <= C_SEXT4 { + return true + } + + case C_SEXT16: + if b >= C_SEXT1 && b <= C_SEXT8 { + return true + } + + case C_LEXT: + if b >= C_SEXT1 && b <= C_SEXT16 { + return true + } + + case C_PPAUTO: + if b == C_PSAUTO { + return true + } + + case C_UAUTO4K: + if b == C_PSAUTO || b == C_PPAUTO { + return true + } + + case C_UAUTO8K: + return cmp(C_UAUTO4K, b) + + case C_UAUTO16K: + return cmp(C_UAUTO8K, b) + + case C_UAUTO32K: + return cmp(C_UAUTO16K, b) + + case C_UAUTO64K: + return cmp(C_UAUTO32K, b) + + case C_NPAUTO: + return cmp(C_NSAUTO, b) + + case C_LAUTO: + return cmp(C_NPAUTO, b) || cmp(C_UAUTO64K, b) + + case C_PSOREG: + if b == C_ZOREG { + return true + } + + case C_PPOREG: + if b == C_ZOREG || b == C_PSOREG { + return true + } + + case C_UOREG4K: + if b == C_ZOREG || b == C_PSAUTO || b == C_PSOREG || b == C_PPAUTO || b == C_PPOREG { + return true + } + + case C_UOREG8K: + return cmp(C_UOREG4K, b) + + case C_UOREG16K: + return cmp(C_UOREG8K, b) + + case C_UOREG32K: + return cmp(C_UOREG16K, b) + + case C_UOREG64K: + return cmp(C_UOREG32K, b) + + case C_NPOREG: + return cmp(C_NSOREG, b) + + case C_LOREG: + return cmp(C_NPOREG, b) || cmp(C_UOREG64K, b) + + case C_LBRA: + if b == C_SBRA { + return true + } + } + + return false +} + +type ocmp []Optab + +func (x ocmp) Len() int { + return len(x) +} + +func (x ocmp) Swap(i, j int) { + x[i], x[j] = x[j], x[i] +} + +func (x ocmp) Less(i, j int) bool { + p1 := &x[i] + p2 := &x[j] + n := int(p1.as) - int(p2.as) + if n != 0 { + return n < 0 + } + n = int(p1.a1) - int(p2.a1) + if n != 0 { + return n < 0 + } + n = int(p1.a2) - int(p2.a2) + if n != 0 { + return n < 0 + } + n = int(p1.a3) - int(p2.a3) + if n != 0 { + return n < 0 + } + n = int(p1.scond) - int(p2.scond) + if n != 0 { + return n < 0 + } + return false +} + +func buildop(ctxt *obj.Link) { + var n int + for i := 0; i < C_GOK; i++ { + for n = 0; n < C_GOK; n++ { + if cmp(n, i) { + xcmp[i][n] = 1 + } + } + } + for n = 0; optab[n].as != obj.AXXX; n++ { + } + sort.Sort(ocmp(optab[:n])) + var r int + var t Oprange + for i := 0; i < n; i++ { + r = int(optab[i].as) + oprange[r].start = optab[i:] + for int(optab[i].as) == r { + i++ + } + oprange[r].stop = optab[i:] + i-- + t = oprange[r] + switch r { + default: + ctxt.Diag("unknown op in build: %v", obj.Aconv(r)) + log.Fatalf("bad code") + + case AADD: + oprange[AADDS] = t + oprange[ASUB] = t + oprange[ASUBS] = t + oprange[AADDW] = t + oprange[AADDSW] = t + oprange[ASUBW] = t + oprange[ASUBSW] = t + + case AAND: /* logical immediate, logical shifted register */ + oprange[AANDS] = t + + oprange[AANDSW] = t + oprange[AANDW] = t + oprange[AEOR] = t + oprange[AEORW] = t + oprange[AORR] = t + oprange[AORRW] = t + + case ABIC: /* only logical shifted register */ + oprange[ABICS] = t + + oprange[ABICSW] = t + oprange[ABICW] = t + oprange[AEON] = t + oprange[AEONW] = t + oprange[AORN] = t + oprange[AORNW] = t + + case ANEG: + oprange[ANEGS] = t + oprange[ANEGSW] = t + oprange[ANEGW] = t + + case AADC: /* rn=Rd */ + oprange[AADCW] = t + + oprange[AADCS] = t + oprange[AADCSW] = t + oprange[ASBC] = t + oprange[ASBCW] = t + oprange[ASBCS] = t + oprange[ASBCSW] = t + + case ANGC: /* rn=REGZERO */ + oprange[ANGCW] = t + + oprange[ANGCS] = t + oprange[ANGCSW] = t + + case ACMP: + oprange[ACMPW] = t + oprange[ACMN] = t + oprange[ACMNW] = t + + case ATST: + oprange[ATSTW] = t + + /* register/register, and shifted */ + case AMVN: + oprange[AMVNW] = t + + case AMOVK: + oprange[AMOVKW] = t + oprange[AMOVN] = t + oprange[AMOVNW] = t + oprange[AMOVZ] = t + oprange[AMOVZW] = t + + case ABEQ: + oprange[ABNE] = t + oprange[ABCS] = t + oprange[ABHS] = t + oprange[ABCC] = t + oprange[ABLO] = t + oprange[ABMI] = t + oprange[ABPL] = t + oprange[ABVS] = t + oprange[ABVC] = t + oprange[ABHI] = t + oprange[ABLS] = t + oprange[ABGE] = t + oprange[ABLT] = t + oprange[ABGT] = t + oprange[ABLE] = t + + case ALSL: + oprange[ALSLW] = t + oprange[ALSR] = t + oprange[ALSRW] = t + oprange[AASR] = t + oprange[AASRW] = t + oprange[AROR] = t + oprange[ARORW] = t + + case ACLS: + oprange[ACLSW] = t + oprange[ACLZ] = t + oprange[ACLZW] = t + oprange[ARBIT] = t + oprange[ARBITW] = t + oprange[AREV] = t + oprange[AREVW] = t + oprange[AREV16] = t + oprange[AREV16W] = t + oprange[AREV32] = t + + case ASDIV: + oprange[ASDIVW] = t + oprange[AUDIV] = t + oprange[AUDIVW] = t + oprange[ACRC32B] = t + oprange[ACRC32CB] = t + oprange[ACRC32CH] = t + oprange[ACRC32CW] = t + oprange[ACRC32CX] = t + oprange[ACRC32H] = t + oprange[ACRC32W] = t + oprange[ACRC32X] = t + + case AMADD: + oprange[AMADDW] = t + oprange[AMSUB] = t + oprange[AMSUBW] = t + oprange[ASMADDL] = t + oprange[ASMSUBL] = t + oprange[AUMADDL] = t + oprange[AUMSUBL] = t + + case AREM: + oprange[AREMW] = t + oprange[AUREM] = t + oprange[AUREMW] = t + + case AMUL: + oprange[AMULW] = t + oprange[AMNEG] = t + oprange[AMNEGW] = t + oprange[ASMNEGL] = t + oprange[ASMULL] = t + oprange[ASMULH] = t + oprange[AUMNEGL] = t + oprange[AUMULH] = t + oprange[AUMULL] = t + + case AMOVB: + oprange[AMOVBU] = t + + case AMOVH: + oprange[AMOVHU] = t + + case AMOVW: + oprange[AMOVWU] = t + + case ABFM: + oprange[ABFMW] = t + oprange[ASBFM] = t + oprange[ASBFMW] = t + oprange[AUBFM] = t + oprange[AUBFMW] = t + + case ABFI: + oprange[ABFIW] = t + oprange[ABFXIL] = t + oprange[ABFXILW] = t + oprange[ASBFIZ] = t + oprange[ASBFIZW] = t + oprange[ASBFX] = t + oprange[ASBFXW] = t + oprange[AUBFIZ] = t + oprange[AUBFIZW] = t + oprange[AUBFX] = t + oprange[AUBFXW] = t + + case AEXTR: + oprange[AEXTRW] = t + + case ASXTB: + oprange[ASXTBW] = t + oprange[ASXTH] = t + oprange[ASXTHW] = t + oprange[ASXTW] = t + oprange[AUXTB] = t + oprange[AUXTH] = t + oprange[AUXTW] = t + oprange[AUXTBW] = t + oprange[AUXTHW] = t + + case ACCMN: + oprange[ACCMNW] = t + oprange[ACCMP] = t + oprange[ACCMPW] = t + + case ACSEL: + oprange[ACSELW] = t + oprange[ACSINC] = t + oprange[ACSINCW] = t + oprange[ACSINV] = t + oprange[ACSINVW] = t + oprange[ACSNEG] = t + oprange[ACSNEGW] = t + + // aliases Rm=Rn, !cond + oprange[ACINC] = t + + oprange[ACINCW] = t + oprange[ACINV] = t + oprange[ACINVW] = t + oprange[ACNEG] = t + oprange[ACNEGW] = t + + // aliases, Rm=Rn=REGZERO, !cond + case ACSET: + oprange[ACSETW] = t + + oprange[ACSETM] = t + oprange[ACSETMW] = t + + case AMOVD, + AMOVBU, + AB, + ABL, + AWORD, + ADWORD, + obj.ARET, + obj.ATEXT, + ACASE, + ABCASE, + ASTP, + ALDP: + break + + case AERET: + oprange[AWFE] = t + oprange[AWFI] = t + oprange[AYIELD] = t + oprange[ASEV] = t + oprange[ASEVL] = t + oprange[ADRPS] = t + + case ACBZ: + oprange[ACBZW] = t + oprange[ACBNZ] = t + oprange[ACBNZW] = t + + case ATBZ: + oprange[ATBNZ] = t + + case AADR, + AADRP: + break + + case ACLREX: + break + + case ASVC: + oprange[AHLT] = t + oprange[AHVC] = t + oprange[ASMC] = t + oprange[ABRK] = t + oprange[ADCPS1] = t + oprange[ADCPS2] = t + oprange[ADCPS3] = t + + case AFADDS: + oprange[AFADDD] = t + oprange[AFSUBS] = t + oprange[AFSUBD] = t + oprange[AFMULS] = t + oprange[AFMULD] = t + oprange[AFNMULS] = t + oprange[AFNMULD] = t + oprange[AFDIVS] = t + oprange[AFMAXD] = t + oprange[AFMAXS] = t + oprange[AFMIND] = t + oprange[AFMINS] = t + oprange[AFMAXNMD] = t + oprange[AFMAXNMS] = t + oprange[AFMINNMD] = t + oprange[AFMINNMS] = t + oprange[AFDIVD] = t + + case AFCVTSD: + oprange[AFCVTDS] = t + oprange[AFABSD] = t + oprange[AFABSS] = t + oprange[AFNEGD] = t + oprange[AFNEGS] = t + oprange[AFSQRTD] = t + oprange[AFSQRTS] = t + oprange[AFRINTNS] = t + oprange[AFRINTND] = t + oprange[AFRINTPS] = t + oprange[AFRINTPD] = t + oprange[AFRINTMS] = t + oprange[AFRINTMD] = t + oprange[AFRINTZS] = t + oprange[AFRINTZD] = t + oprange[AFRINTAS] = t + oprange[AFRINTAD] = t + oprange[AFRINTXS] = t + oprange[AFRINTXD] = t + oprange[AFRINTIS] = t + oprange[AFRINTID] = t + oprange[AFCVTDH] = t + oprange[AFCVTHS] = t + oprange[AFCVTHD] = t + oprange[AFCVTSH] = t + + case AFCMPS: + oprange[AFCMPD] = t + oprange[AFCMPES] = t + oprange[AFCMPED] = t + + case AFCCMPS: + oprange[AFCCMPD] = t + oprange[AFCCMPES] = t + oprange[AFCCMPED] = t + + case AFCSELD: + oprange[AFCSELS] = t + + case AFMOVS, + AFMOVD: + break + + case AFCVTZSD: + oprange[AFCVTZSDW] = t + oprange[AFCVTZSS] = t + oprange[AFCVTZSSW] = t + oprange[AFCVTZUD] = t + oprange[AFCVTZUDW] = t + oprange[AFCVTZUS] = t + oprange[AFCVTZUSW] = t + + case ASCVTFD: + oprange[ASCVTFS] = t + oprange[ASCVTFWD] = t + oprange[ASCVTFWS] = t + oprange[AUCVTFD] = t + oprange[AUCVTFS] = t + oprange[AUCVTFWD] = t + oprange[AUCVTFWS] = t + + case ASYS: + oprange[AAT] = t + oprange[ADC] = t + oprange[AIC] = t + oprange[ATLBI] = t + + case ASYSL, + AHINT: + break + + case ADMB: + oprange[ADSB] = t + oprange[AISB] = t + + case AMRS, + AMSR: + break + + case ALDAR: + oprange[ALDARW] = t + fallthrough + + case ALDXR: + oprange[ALDXRB] = t + oprange[ALDXRH] = t + oprange[ALDXRW] = t + + case ALDAXR: + oprange[ALDAXRW] = t + + case ALDXP: + oprange[ALDXPW] = t + + case ASTLR: + oprange[ASTLRW] = t + + case ASTXR: + oprange[ASTXRB] = t + oprange[ASTXRH] = t + oprange[ASTXRW] = t + + case ASTLXR: + oprange[ASTLXRW] = t + + case ASTXP: + oprange[ASTXPW] = t + + case AAESD: + oprange[AAESE] = t + oprange[AAESMC] = t + oprange[AAESIMC] = t + oprange[ASHA1H] = t + oprange[ASHA1SU1] = t + oprange[ASHA256SU0] = t + + case ASHA1C: + oprange[ASHA1P] = t + oprange[ASHA1M] = t + oprange[ASHA1SU0] = t + oprange[ASHA256H] = t + oprange[ASHA256H2] = t + oprange[ASHA256SU1] = t + + case obj.ANOP, + obj.AUNDEF, + obj.AUSEFIELD, + obj.AFUNCDATA, + obj.APCDATA, + obj.ADUFFZERO, + obj.ADUFFCOPY: + break + } + } +} + +func chipfloat7(ctxt *obj.Link, e float64) int { + ei := math.Float64bits(e) + l := uint32(int32(ei)) + h := uint32(int32(ei >> 32)) + + if l != 0 || h&0xffff != 0 { + return -1 + } + h1 := h & 0x7fc00000 + if h1 != 0x40000000 && h1 != 0x3fc00000 { + return -1 + } + n := 0 + + // sign bit (a) + if h&0x80000000 != 0 { + n |= 1 << 7 + } + + // exp sign bit (b) + if h1 == 0x3fc00000 { + n |= 1 << 6 + } + + // rest of exp and mantissa (cd-efgh) + n |= int((h >> 16) & 0x3f) + + //print("match %.8lux %.8lux %d\n", l, h, n); + return n +} + +/* form offset parameter to SYS; special register number */ +func SYSARG5(op0 int, op1 int, Cn int, Cm int, op2 int) int { + return op0<<19 | op1<<16 | Cn<<12 | Cm<<8 | op2<<5 +} + +func SYSARG4(op1 int, Cn int, Cm int, op2 int) int { + return SYSARG5(0, op1, Cn, Cm, op2) +} + +func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { + var lastcase *obj.Prog + o1 := uint32(0) + o2 := uint32(0) + o3 := uint32(0) + o4 := uint32(0) + o5 := uint32(0) + if false { /*debug['P']*/ + fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_) + } + switch o.type_ { + default: + ctxt.Diag("unknown asm %d", o.type_) + prasm(p) + + case 0: /* pseudo ops */ + break + + case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */ + o1 = oprrr(ctxt, int(p.As)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 2: /* add/sub $(uimm12|uimm24)[,R],R; cmp $(uimm12|uimm24),R */ + o1 = opirr(ctxt, int(p.As)) + + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + if (o1 & Sbit) == 0 { + ctxt.Diag("ineffective ZR destination\n%v", p) + } + rt = REGZERO + } + + r := int(p.Reg) + if r == 0 { + r = rt + } + v := int32(regoff(ctxt, &p.From)) + o1 = oaddi(ctxt, int32(o1), v, r, rt) + + case 3: /* op R<>= 12 + o1 |= 1 << 22 /* shift, by 12 */ + } + + o1 |= ((uint32(v) & 0xFFF) << 10) | (uint32(r&31) << 5) | uint32(rt&31) + + case 5: /* b s; bl s */ + o1 = opbra(ctxt, int(p.As)) + + if p.To.Sym == nil { + o1 |= uint32(brdist(ctxt, p, 0, 26, 2)) + break + } + + rel := obj.Addrel(ctxt.Cursym) + rel.Off = int32(ctxt.Pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Add = int64(o1) | (p.To.Offset>>2)&0x3ffffff + rel.Type = obj.R_CALLARM64 + + case 6: /* b ,O(R); bl ,O(R) */ + o1 = opbrr(ctxt, int(p.As)) + + o1 |= uint32(p.To.Reg&31) << 5 + rel := obj.Addrel(ctxt.Cursym) + rel.Off = int32(ctxt.Pc) + rel.Siz = 0 + rel.Type = obj.R_CALLIND + + case 7: /* beq s */ + o1 = opbra(ctxt, int(p.As)) + + o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5) + + case 8: /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */ + rt := int(p.To.Reg) + + rf := int(p.Reg) + if rf == 0 { + rf = rt + } + v := int32(p.From.Offset) + switch p.As { + case AASR: + o1 = opbfm(ctxt, ASBFM, int(v), 63, rf, rt) + + case AASRW: + o1 = opbfm(ctxt, ASBFMW, int(v), 31, rf, rt) + + case ALSL: + o1 = opbfm(ctxt, AUBFM, int((64-v)&63), int(63-v), rf, rt) + + case ALSLW: + o1 = opbfm(ctxt, AUBFMW, int((32-v)&31), int(31-v), rf, rt) + + case ALSR: + o1 = opbfm(ctxt, AUBFM, int(v), 63, rf, rt) + + case ALSRW: + o1 = opbfm(ctxt, AUBFMW, int(v), 31, rf, rt) + + case AROR: + o1 = opextr(ctxt, AEXTR, v, rf, rf, rt) + + case ARORW: + o1 = opextr(ctxt, AEXTRW, v, rf, rf, rt) + + default: + ctxt.Diag("bad shift $con\n%v", ctxt.Curp) + break + } + + case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */ + o1 = oprrr(ctxt, int(p.As)) + + r := int(p.Reg) + if r == 0 { + r = int(p.To.Reg) + } + o1 |= (uint32(p.From.Reg&31) << 16) | (uint32(r&31) << 5) | uint32(p.To.Reg&31) + + case 10: /* brk/hvc/.../svc [$con] */ + o1 = opimm(ctxt, int(p.As)) + + if p.To.Type != obj.TYPE_NONE { + o1 |= uint32((p.To.Offset & 0xffff) << 5) + } + + case 11: /* dword */ + aclass(ctxt, &p.To) + + o1 = uint32(ctxt.Instoffset) + o2 = uint32(ctxt.Instoffset >> 32) + if p.To.Sym != nil { + rel := obj.Addrel(ctxt.Cursym) + rel.Off = int32(ctxt.Pc) + rel.Siz = 8 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = obj.R_ADDR + o2 = 0 + o1 = o2 + } + + case 12: /* movT $vcon, reg */ + o1 = omovlit(ctxt, int(p.As), p, &p.From, int(p.To.Reg)) + + case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */ + o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP) + + if !(o1 != 0) { + break + } + rt := int(p.To.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + r := int(p.Reg) + if r == 0 { + r = rt + } + if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) { + o2 = opxrrr(ctxt, int(p.As)) + o2 |= REGTMP & 31 << 16 + o2 |= LSL0_64 + } else { + o2 = oprrr(ctxt, int(p.As)) + o2 |= REGTMP & 31 << 16 /* shift is 0 */ + } + + o2 |= uint32(r&31) << 5 + o2 |= uint32(rt & 31) + + case 14: /* word */ + if aclass(ctxt, &p.To) == C_ADDR { + ctxt.Diag("address constant needs DWORD\n%v", p) + } + o1 = uint32(ctxt.Instoffset) + if p.To.Sym != nil { + // This case happens with words generated + // in the PC stream as part of the literal pool. + rel := obj.Addrel(ctxt.Cursym) + + rel.Off = int32(ctxt.Pc) + rel.Siz = 4 + rel.Sym = p.To.Sym + rel.Add = p.To.Offset + rel.Type = obj.R_ADDR + o1 = 0 + } + + case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub Rm,Rn,Ra,Rd */ + o1 = oprrr(ctxt, int(p.As)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + var r int + var ra int + if p.From3.Type == obj.TYPE_REG { + r = int(p.From3.Reg) + ra = int(p.Reg) + if ra == 0 { + ra = REGZERO + } + } else { + r = int(p.Reg) + if r == 0 { + r = rt + } + ra = REGZERO + } + + o1 |= (uint32(rf&31) << 16) | (uint32(ra&31) << 10) | (uint32(r&31) << 5) | uint32(rt&31) + + case 16: /* XremY R[,R],R -> XdivY; XmsubY */ + o1 = oprrr(ctxt, int(p.As)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | REGTMP&31 + o2 = oprrr(ctxt, AMSUBW) + o2 |= o1 & (1 << 31) /* same size */ + o2 |= (uint32(rf&31) << 16) | (uint32(r&31) << 10) | (REGTMP & 31 << 5) | uint32(rt&31) + + case 17: /* op Rm,[Rn],Rd; default Rn=ZR */ + o1 = oprrr(ctxt, int(p.As)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + r := int(p.Reg) + if p.To.Type == obj.TYPE_NONE { + rt = REGZERO + } + if r == 0 { + r = REGZERO + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */ + o1 = oprrr(ctxt, int(p.As)) + + cond := int(p.From.Reg) + r := int(p.Reg) + var rf int + if r != 0 { + if p.From3.Type == obj.TYPE_NONE { + /* CINC/CINV/CNEG */ + rf = r + + cond ^= 1 + } else { + rf = int(p.From3.Reg) /* CSEL */ + } + } else { + /* CSET */ + if p.From3.Type != obj.TYPE_NONE { + ctxt.Diag("invalid combination\n%v", p) + } + rf = REGZERO + r = rf + cond ^= 1 + } + + rt := int(p.To.Reg) + o1 |= (uint32(r&31) << 16) | (uint32(cond) << 12) | (uint32(rf&31) << 5) | uint32(rt&31) + + case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */ + nzcv := int(p.To.Offset) + + cond := int(p.From.Reg) + var rf int + if p.From3.Type == obj.TYPE_REG { + o1 = oprrr(ctxt, int(p.As)) + rf = int(p.From3.Reg) /* Rm */ + } else { + o1 = opirr(ctxt, int(p.As)) + rf = int(p.From3.Offset & 0x1F) + } + + o1 |= (uint32(rf&31) << 16) | (uint32(cond) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv) + + case 20: /* movT R,O(R) -> strT */ + v := int32(regoff(ctxt, &p.To)) + + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + if v < 0 { /* unscaled 9-bit signed */ + o1 = olsr9s(ctxt, int32(opstr9(ctxt, int(p.As))), v, r, int(p.From.Reg)) + } else { + v = int32(offsetshift(ctxt, int64(v), int(o.a3))) + o1 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), v, r, int(p.From.Reg)) + } + + case 21: /* movT O(R),R -> ldrT */ + v := int32(regoff(ctxt, &p.From)) + + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + if v < 0 { /* unscaled 9-bit signed */ + o1 = olsr9s(ctxt, int32(opldr9(ctxt, int(p.As))), v, r, int(p.To.Reg)) + } else { + v = int32(offsetshift(ctxt, int64(v), int(o.a1))) + + //print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1); + o1 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), v, r, int(p.To.Reg)) + } + + case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */ + v := int32(p.From.Offset) + + if v < -256 || v > 255 { + ctxt.Diag("offset out of range\n%v", p) + } + o1 = opldrpp(ctxt, int(p.As)) + if o.scond == C_XPOST { + o1 |= 1 << 10 + } else { + o1 |= 3 << 10 + } + o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.From.Reg&31) << 5) | uint32(p.To.Reg&31) + + case 23: /* movT R,(R)O!; movT O(R)!, R -> strT */ + v := int32(p.To.Offset) + + if v < -256 || v > 255 { + ctxt.Diag("offset out of range\n%v", p) + } + o1 = LD2STR(opldrpp(ctxt, int(p.As))) + if o.scond == C_XPOST { + o1 |= 1 << 10 + } else { + o1 |= 3 << 10 + } + o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.To.Reg&31) << 5) | uint32(p.From.Reg&31) + + case 24: /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */ + rf := int(p.From.Reg) + rt := int(p.To.Reg) + s := bool2int(rf == REGSP || rt == REGSP) + if p.As == AMVN || p.As == AMVNW { + if s != 0 { + ctxt.Diag("illegal SP reference\n%v", p) + } + o1 = oprrr(ctxt, int(p.As)) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + } else if s != 0 { + o1 = opirr(ctxt, int(p.As)) + o1 |= (uint32(rf&31) << 5) | uint32(rt&31) + } else { + o1 = oprrr(ctxt, int(p.As)) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + } + + case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */ + o1 = oprrr(ctxt, int(p.As)) + + rf := int(p.From.Reg) + rt := int(p.To.Reg) + o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + + case 26: /* negX Rm< subX Rm< strT */ + s := movesize(int(o.as)) + + if s < 0 { + ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(int(p.As)), obj.Aconv(int(o.as)), p) + } + v := int32(regoff(ctxt, &p.To)) + if v < 0 { + ctxt.Diag("negative large offset\n%v", p) + } + if (v & ((1 << uint(s)) - 1)) != 0 { + ctxt.Diag("misaligned offset\n%v", p) + } + hi := v - (v & (0xFFF << uint(s))) + if (hi & 0xFFF) != 0 { + ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p) + } + + //fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF); + r := int(p.To.Reg) + + if r == 0 { + r = int(o.param) + } + o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP) + o2 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg)) + + case 31: /* movT L(R), R -> ldrT */ + s := movesize(int(o.as)) + + if s < 0 { + ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(int(p.As)), obj.Aconv(int(o.as)), p) + } + v := int32(regoff(ctxt, &p.From)) + if v < 0 { + ctxt.Diag("negative large offset\n%v", p) + } + if (v & ((1 << uint(s)) - 1)) != 0 { + ctxt.Diag("misaligned offset\n%v", p) + } + hi := v - (v & (0xFFF << uint(s))) + if (hi & 0xFFF) != 0 { + ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p) + } + + //fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF); + r := int(p.From.Reg) + + if r == 0 { + r = int(o.param) + } + o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP) + o2 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg)) + + case 32: /* mov $con, R -> movz/movn */ + r := 32 + + if p.As == AMOVD { + r = 64 + } + d := p.From.Offset + s := movcon(d) + if s < 0 || s >= r { + d = ^d + s = movcon(d) + if s < 0 || s >= r { + ctxt.Diag("impossible move wide: %#x\n%v", uint64(p.From.Offset), p) + } + if p.As == AMOVD { + o1 = opirr(ctxt, AMOVN) + } else { + o1 = opirr(ctxt, AMOVNW) + } + } else { + if p.As == AMOVD { + o1 = opirr(ctxt, AMOVZ) + } else { + o1 = opirr(ctxt, AMOVZW) + } + } + + rt := int(p.To.Reg) + o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31)) + + case 33: /* movk $uimm16 << pos */ + o1 = opirr(ctxt, int(p.As)) + + d := p.From.Offset + if (d >> 16) != 0 { + ctxt.Diag("requires uimm16\n%v", p) + } + s := 0 + if p.From3.Type != obj.TYPE_NONE { + if p.From3.Type != obj.TYPE_CONST { + ctxt.Diag("missing bit position\n%v", p) + } + s = int(p.From3.Offset / 16) + if (s*16&0xF) != 0 || s >= 4 || (o1&S64) == 0 && s >= 2 { + ctxt.Diag("illegal bit position\n%v", p) + } + } + + rt := int(p.To.Reg) + o1 |= uint32(((d & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31)) + + case 34: /* mov $lacon,R */ + o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP) + + if !(o1 != 0) { + break + } + o2 = opxrrr(ctxt, AADD) + o2 |= REGTMP & 31 << 16 + o2 |= LSL0_64 + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 |= uint32(r&31) << 5 + o2 |= uint32(p.To.Reg & 31) + + case 35: /* mov SPR,R -> mrs */ + o1 = oprrr(ctxt, AMRS) + + v := int32(p.From.Offset) + if (o1 & uint32(v&^(3<<19))) != 0 { + ctxt.Diag("MRS register value overlap\n%v", p) + } + o1 |= uint32(v) + o1 |= uint32(p.To.Reg & 31) + + case 36: /* mov R,SPR */ + o1 = oprrr(ctxt, AMSR) + + v := int32(p.To.Offset) + if (o1 & uint32(v&^(3<<19))) != 0 { + ctxt.Diag("MSR register value overlap\n%v", p) + } + o1 |= uint32(v) + o1 |= uint32(p.From.Reg & 31) + + case 37: /* mov $con,PSTATEfield -> MSR [immediate] */ + if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 { + ctxt.Diag("illegal immediate for PSTATE field\n%v", p) + } + o1 = opirr(ctxt, AMSR) + o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */ + v := int32(0) + for i := 0; i < len(pstatefield); i++ { + if int64(pstatefield[i].a) == p.To.Offset { + v = int32(pstatefield[i].b) + break + } + } + + if v == 0 { + ctxt.Diag("illegal PSTATE field for immediate move\n%v", p) + } + o1 |= uint32(v) + + case 38: /* clrex [$imm] */ + o1 = opimm(ctxt, int(p.As)) + + if p.To.Type == obj.TYPE_NONE { + o1 |= 0xF << 8 + } else { + o1 |= uint32((p.To.Offset & 0xF) << 8) + } + + case 39: /* cbz R, rel */ + o1 = opirr(ctxt, int(p.As)) + + o1 |= uint32(p.From.Reg & 31) + o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5) + + case 40: /* tbz */ + o1 = opirr(ctxt, int(p.As)) + + v := int32(p.From.Offset) + if v < 0 || v > 63 { + ctxt.Diag("illegal bit number\n%v", p) + } + o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19) + o1 |= uint32(brdist(ctxt, p, 0, 14, 2) << 5) + o1 |= uint32(p.Reg) + + case 41: /* eret, nop, others with no operands */ + o1 = op0(ctxt, int(p.As)) + + case 42: /* bfm R,r,s,R */ + o1 = opbfm(ctxt, int(p.As), int(p.From.Offset), int(p.From3.Offset), int(p.Reg), int(p.To.Reg)) + + case 43: /* bfm aliases */ + r := int(p.From.Offset) + + s := int(p.From3.Offset) + rf := int(p.Reg) + rt := int(p.To.Reg) + if rf == 0 { + rf = rt + } + switch p.As { + case ABFI: + o1 = opbfm(ctxt, ABFM, 64-r, s-1, rf, rt) + + case ABFIW: + o1 = opbfm(ctxt, ABFMW, 32-r, s-1, rf, rt) + + case ABFXIL: + o1 = opbfm(ctxt, ABFM, r, r+s-1, rf, rt) + + case ABFXILW: + o1 = opbfm(ctxt, ABFMW, r, r+s-1, rf, rt) + + case ASBFIZ: + o1 = opbfm(ctxt, ASBFM, 64-r, s-1, rf, rt) + + case ASBFIZW: + o1 = opbfm(ctxt, ASBFMW, 32-r, s-1, rf, rt) + + case ASBFX: + o1 = opbfm(ctxt, ASBFM, r, r+s-1, rf, rt) + + case ASBFXW: + o1 = opbfm(ctxt, ASBFMW, r, r+s-1, rf, rt) + + case AUBFIZ: + o1 = opbfm(ctxt, AUBFM, 64-r, s-1, rf, rt) + + case AUBFIZW: + o1 = opbfm(ctxt, AUBFMW, 32-r, s-1, rf, rt) + + case AUBFX: + o1 = opbfm(ctxt, AUBFM, r, r+s-1, rf, rt) + + case AUBFXW: + o1 = opbfm(ctxt, AUBFMW, r, r+s-1, rf, rt) + + default: + ctxt.Diag("bad bfm alias\n%v", ctxt.Curp) + break + } + + case 44: /* extr $b, Rn, Rm, Rd */ + o1 = opextr(ctxt, int(p.As), int32(p.From.Offset), int(p.From3.Reg), int(p.Reg), int(p.To.Reg)) + + case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */ + rf := int(p.From.Reg) + + rt := int(p.To.Reg) + as := int(p.As) + if rf == REGZERO { + as = AMOVWU /* clearer in disassembly */ + } + switch as { + case AMOVB, + ASXTB: + o1 = opbfm(ctxt, ASBFM, 0, 7, rf, rt) + + case AMOVH, + ASXTH: + o1 = opbfm(ctxt, ASBFM, 0, 15, rf, rt) + + case AMOVW, + ASXTW: + o1 = opbfm(ctxt, ASBFM, 0, 31, rf, rt) + + case AMOVBU, + AUXTB: + o1 = opbfm(ctxt, AUBFM, 0, 7, rf, rt) + + case AMOVHU, + AUXTH: + o1 = opbfm(ctxt, AUBFM, 0, 15, rf, rt) + + case AMOVWU: + o1 = oprrr(ctxt, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) + + case AUXTW: + o1 = opbfm(ctxt, AUBFM, 0, 31, rf, rt) + + case ASXTBW: + o1 = opbfm(ctxt, ASBFMW, 0, 7, rf, rt) + + case ASXTHW: + o1 = opbfm(ctxt, ASBFMW, 0, 15, rf, rt) + + case AUXTBW: + o1 = opbfm(ctxt, AUBFMW, 0, 7, rf, rt) + + case AUXTHW: + o1 = opbfm(ctxt, AUBFMW, 0, 15, rf, rt) + + default: + ctxt.Diag("bad sxt %v", obj.Aconv(as)) + break + } + + case 46: /* cls */ + o1 = opbit(ctxt, int(p.As)) + + o1 |= uint32(p.From.Reg&31) << 5 + o1 |= uint32(p.To.Reg & 31) + + case 47: /* movT R,V(R) -> strT (huge offset) */ + o1 = omovlit(ctxt, AMOVW, p, &p.To, REGTMP) + + if !(o1 != 0) { + break + } + r := int(p.To.Reg) + if r == 0 { + r = int(o.param) + } + o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.From.Reg)) + + case 48: /* movT V(R), R -> ldrT (huge offset) */ + o1 = omovlit(ctxt, AMOVW, p, &p.From, REGTMP) + + if !(o1 != 0) { + break + } + r := int(p.From.Reg) + if r == 0 { + r = int(o.param) + } + o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.To.Reg)) + + case 50: /* sys/sysl */ + o1 = opirr(ctxt, int(p.As)) + + if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 { + ctxt.Diag("illegal SYS argument\n%v", p) + } + o1 |= uint32(p.From.Offset) + if p.To.Type == obj.TYPE_REG { + o1 |= uint32(p.To.Reg & 31) + } else if p.Reg != 0 { + o1 |= uint32(p.Reg & 31) + } else { + o1 |= 0x1F + } + + case 51: /* dmb */ + o1 = opirr(ctxt, int(p.As)) + + if p.From.Type == obj.TYPE_CONST { + o1 |= uint32((p.From.Offset & 0xF) << 8) + } + + case 52: /* hint */ + o1 = opirr(ctxt, int(p.As)) + + o1 |= uint32((p.From.Offset & 0x7F) << 5) + + case 53: /* and/or/eor/bic/... $bimmN, Rn, Rd -> op (N,r,s), Rn, Rd */ + ctxt.Diag("bitmask immediate not implemented\n%v", p) + + case 54: /* floating point arith */ + o1 = oprrr(ctxt, int(p.As)) + + var rf int + if p.From.Type == obj.TYPE_CONST { + rf = chipfloat7(ctxt, p.From.U.Dval) + if rf < 0 || true { + ctxt.Diag("invalid floating-point immediate\n%v", p) + rf = 0 + } + + rf |= (1 << 3) + } else { + rf = int(p.From.Reg) + } + rt := int(p.To.Reg) + r := int(p.Reg) + if (o1&(0x1F<<24)) == (0x1E<<24) && (o1&(1<<11)) == 0 { /* monadic */ + r = rf + rf = 0 + } else if r == 0 { + r = rt + } + o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + + case 56: /* floating point compare */ + o1 = oprrr(ctxt, int(p.As)) + + var rf int + if p.From.Type == obj.TYPE_CONST { + o1 |= 8 /* zero */ + rf = 0 + } else { + rf = int(p.From.Reg) + } + rt := int(p.Reg) + o1 |= uint32(rf&31)<<16 | uint32(rt&31)<<5 + + case 57: /* floating point conditional compare */ + o1 = oprrr(ctxt, int(p.As)) + + cond := int(p.From.Reg) + nzcv := int(p.To.Offset) + if nzcv&^0xF != 0 { + ctxt.Diag("implausible condition\n%v", p) + } + rf := int(p.Reg) + if p.From3.Reg < REG_F0 || p.From3.Reg > REG_F31 { + ctxt.Diag("illegal FCCMP\n%v", p) + } + rt := int(p.From3.Reg) + o1 |= uint32(rf&31)<<16 | uint32(cond)<<12 | uint32(rt&31)<<5 | uint32(nzcv) + + case 58: /* ldar/ldxr/ldaxr */ + o1 = opload(ctxt, int(p.As)) + + o1 |= 0x1F << 16 + o1 |= uint32(p.From.Reg) << 5 + if p.Reg != 0 { + o1 |= uint32(p.Reg) << 10 + } else { + o1 |= 0x1F << 10 + } + o1 |= uint32(p.To.Reg & 31) + + case 59: /* stxr/stlxr */ + o1 = opstore(ctxt, int(p.As)) + + if p.To2.Type != obj.TYPE_NONE { + o1 |= uint32(p.To2.Reg&31) << 16 + } else { + o1 |= 0x1F << 16 + } + + // TODO(aram): add support for STXP + o1 |= uint32(p.To.Reg&31) << 5 + + o1 |= uint32(p.From.Reg & 31) + + case 60: /* adrp label,r */ + d := brdist(ctxt, p, 12, 21, 0) + + o1 = ADR(1, uint32(d), uint32(p.To.Reg)) + + case 61: /* adr label, r */ + d := brdist(ctxt, p, 0, 21, 0) + + o1 = ADR(0, uint32(d), uint32(p.To.Reg)) + + case 62: /* case Rv, Rt -> adr tab, Rt; movw Rt[R<<2], Rl; add Rt, Rl; br (Rl) */ + // adr 4(pc), Rt + o1 = ADR(0, 4*4, uint32(p.To.Reg)) + // movw Rt[Rv<<2], REGTMP + o2 = (2 << 30) | (7 << 27) | (2 << 22) | (1 << 21) | (3 << 13) | (1 << 12) | (2 << 10) | (uint32(p.From.Reg&31) << 16) | (uint32(p.To.Reg&31) << 5) | REGTMP&31 + // add Rt, REGTMP + o3 = oprrr(ctxt, AADD) | (uint32(p.To.Reg) << 16) | (REGTMP << 5) | REGTMP + // br (REGTMP) + o4 = (0x6b << 25) | (0x1F << 16) | (REGTMP & 31 << 5) + lastcase = p + + case 63: /* bcase */ + if lastcase == nil { + ctxt.Diag("missing CASE\n%v", p) + break + } + + if p.Pcond != nil { + o1 = uint32(p.Pcond.Pc - (lastcase.Pc + 4*4)) + ctxt.Diag("FIXME: some relocation needed in bcase\n%v", p) + } + + /* reloc ops */ + case 64: /* movT R,addr */ + o1 = omovlit(ctxt, AMOVD, p, &p.To, REGTMP) + + if !(o1 != 0) { + break + } + o2 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), 0, REGTMP, int(p.From.Reg)) + + case 65: /* movT addr,R */ + o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP) + + if !(o1 != 0) { + break + } + o2 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), 0, REGTMP, int(p.To.Reg)) + + case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */ + v := int32(p.From.Offset) + + if v < -512 || v > 504 { + ctxt.Diag("offset out of range\n%v", p) + } + if o.scond == C_XPOST { + o1 |= 1 << 23 + } else { + o1 |= 3 << 23 + } + o1 |= 1 << 22 + o1 |= uint32(int64(2<<30|5<<27|((uint32(v)/8)&0x7f)<<15) | p.To.Offset<<10 | int64(uint32(p.From.Reg&31)<<5) | int64(p.To.Reg&31)) + + case 67: /* stp (r1, r2), O(R)!; stp (r1, r2), (R)O! */ + v := int32(p.To.Offset) + + if v < -512 || v > 504 { + ctxt.Diag("offset out of range\n%v", p) + } + if o.scond == C_XPOST { + o1 |= 1 << 23 + } else { + o1 |= 3 << 23 + } + o1 |= uint32(int64(2<<30|5<<27|((uint32(v)/8)&0x7f)<<15) | p.From.Offset<<10 | int64(uint32(p.To.Reg&31)<<5) | int64(p.From.Reg&31)) + + // This is supposed to be something that stops execution. + // It's not supposed to be reached, ever, but if it is, we'd + // like to be able to tell how we got there. Assemble as + // 0xbea71700 which is guaranteed to raise undefined instruction + // exception. + case 90: + o1 = 0xbea71700 + + break + } + + out[0] = o1 + out[1] = o2 + out[2] = o3 + out[3] = o4 + out[4] = o5 + return +} + +/* + * basic Rm op Rn -> Rd (using shifted register with 0) + * also op Rn -> Rt + * also Rm*Rn op Ra -> Rd + */ +func oprrr(ctxt *obj.Link, a int) uint32 { + switch a { + case AADC: + return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case AADCW: + return S32 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case AADCS: + return S64 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case AADCSW: + return S32 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case ANGC, + ASBC: + return S64 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case ANGCS, + ASBCS: + return S64 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case ANGCW, + ASBCW: + return S32 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10 + + case ANGCSW, + ASBCSW: + return S32 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10 + + case AADD: + return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case AADDW: + return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMN, + AADDS: + return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMNW, + AADDSW: + return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMP, + ASUBS: + return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case ACMPW, + ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10 + + case AAND: + return S64 | 0<<29 | 0xA<<24 + + case AANDW: + return S32 | 0<<29 | 0xA<<24 + + case AMOVD, + AORR: + return S64 | 1<<29 | 0xA<<24 + + // case AMOVW: + case AMOVWU, + AORRW: + return S32 | 1<<29 | 0xA<<24 + + case AEOR: + return S64 | 2<<29 | 0xA<<24 + + case AEORW: + return S32 | 2<<29 | 0xA<<24 + + case AANDS: + return S64 | 3<<29 | 0xA<<24 + + case AANDSW: + return S32 | 3<<29 | 0xA<<24 + + case ABIC: + return S64 | 0<<29 | 0xA<<24 | 1<<21 + + case ABICW: + return S32 | 0<<29 | 0xA<<24 | 1<<21 + + case ABICS: + return S64 | 3<<29 | 0xA<<24 | 1<<21 + + case ABICSW: + return S32 | 3<<29 | 0xA<<24 | 1<<21 + + case AEON: + return S64 | 2<<29 | 0xA<<24 | 1<<21 + + case AEONW: + return S32 | 2<<29 | 0xA<<24 | 1<<21 + + case AMVN, + AORN: + return S64 | 1<<29 | 0xA<<24 | 1<<21 + + case AMVNW, + AORNW: + return S32 | 1<<29 | 0xA<<24 | 1<<21 + + case AASR: + return S64 | OPDP2(10) /* also ASRV */ + + case AASRW: + return S32 | OPDP2(10) + + case ALSL: + return S64 | OPDP2(8) + + case ALSLW: + return S32 | OPDP2(8) + + case ALSR: + return S64 | OPDP2(9) + + case ALSRW: + return S32 | OPDP2(9) + + case AROR: + return S64 | OPDP2(11) + + case ARORW: + return S32 | OPDP2(11) + + case ACCMN: + return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* cond<<12 | nzcv<<0 */ + + case ACCMNW: + return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 + + case ACCMP: + return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMPW: + return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 + + case ACRC32B: + return S32 | OPDP2(16) + + case ACRC32H: + return S32 | OPDP2(17) + + case ACRC32W: + return S32 | OPDP2(18) + + case ACRC32X: + return S64 | OPDP2(19) + + case ACRC32CB: + return S32 | OPDP2(20) + + case ACRC32CH: + return S32 | OPDP2(21) + + case ACRC32CW: + return S32 | OPDP2(22) + + case ACRC32CX: + return S64 | OPDP2(23) + + case ACSEL: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSELW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSET: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACSETW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACSETM: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACSETMW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACINC, + ACSINC: + return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACINCW, + ACSINCW: + return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACINV, + ACSINV: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACINVW, + ACSINVW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10 + + case ACNEG, + ACSNEG: + return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case ACNEGW, + ACSNEGW: + return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10 + + case AMUL, + AMADD: + return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15 + + case AMULW, + AMADDW: + return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15 + + case AMNEG, + AMSUB: + return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15 + + case AMNEGW, + AMSUBW: + return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15 + + case AMRS: + return SYSOP(1, 2, 0, 0, 0, 0, 0) + + case AMSR: + return SYSOP(0, 2, 0, 0, 0, 0, 0) + + case ANEG: + return S64 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21 + + case ANEGW: + return S32 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21 + + case ANEGS: + return S64 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21 + + case ANEGSW: + return S32 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21 + + case AREM, + ASDIV: + return S64 | OPDP2(3) + + case AREMW, + ASDIVW: + return S32 | OPDP2(3) + + case ASMULL, + ASMADDL: + return OPDP3(1, 0, 1, 0) + + case ASMNEGL, + ASMSUBL: + return OPDP3(1, 0, 1, 1) + + case ASMULH: + return OPDP3(1, 0, 2, 0) + + case AUMULL, + AUMADDL: + return OPDP3(1, 0, 5, 0) + + case AUMNEGL, + AUMSUBL: + return OPDP3(1, 0, 5, 1) + + case AUMULH: + return OPDP3(1, 0, 6, 0) + + case AUREM, + AUDIV: + return S64 | OPDP2(2) + + case AUREMW, + AUDIVW: + return S32 | OPDP2(2) + + case AAESE: + return 0x4E<<24 | 2<<20 | 8<<16 | 4<<12 | 2<<10 + + case AAESD: + return 0x4E<<24 | 2<<20 | 8<<16 | 5<<12 | 2<<10 + + case AAESMC: + return 0x4E<<24 | 2<<20 | 8<<16 | 6<<12 | 2<<10 + + case AAESIMC: + return 0x4E<<24 | 2<<20 | 8<<16 | 7<<12 | 2<<10 + + case ASHA1C: + return 0x5E<<24 | 0<<12 + + case ASHA1P: + return 0x5E<<24 | 1<<12 + + case ASHA1M: + return 0x5E<<24 | 2<<12 + + case ASHA1SU0: + return 0x5E<<24 | 3<<12 + + case ASHA256H: + return 0x5E<<24 | 4<<12 + + case ASHA256H2: + return 0x5E<<24 | 5<<12 + + case ASHA256SU1: + return 0x5E<<24 | 6<<12 + + case ASHA1H: + return 0x5E<<24 | 2<<20 | 8<<16 | 0<<12 | 2<<10 + + case ASHA1SU1: + return 0x5E<<24 | 2<<20 | 8<<16 | 1<<12 | 2<<10 + + case ASHA256SU0: + return 0x5E<<24 | 2<<20 | 8<<16 | 2<<12 | 2<<10 + + case AFCVTZSD: + return FPCVTI(1, 0, 1, 3, 0) + + case AFCVTZSDW: + return FPCVTI(0, 0, 1, 3, 0) + + case AFCVTZSS: + return FPCVTI(1, 0, 0, 3, 0) + + case AFCVTZSSW: + return FPCVTI(0, 0, 0, 3, 0) + + case AFCVTZUD: + return FPCVTI(1, 0, 1, 3, 1) + + case AFCVTZUDW: + return FPCVTI(0, 0, 1, 3, 1) + + case AFCVTZUS: + return FPCVTI(1, 0, 0, 3, 1) + + case AFCVTZUSW: + return FPCVTI(0, 0, 0, 3, 1) + + case ASCVTFD: + return FPCVTI(1, 0, 1, 0, 2) + + case ASCVTFS: + return FPCVTI(1, 0, 0, 0, 2) + + case ASCVTFWD: + return FPCVTI(0, 0, 1, 0, 2) + + case ASCVTFWS: + return FPCVTI(0, 0, 0, 0, 2) + + case AUCVTFD: + return FPCVTI(1, 0, 1, 0, 3) + + case AUCVTFS: + return FPCVTI(1, 0, 0, 0, 3) + + case AUCVTFWD: + return FPCVTI(0, 0, 1, 0, 3) + + case AUCVTFWS: + return FPCVTI(0, 0, 0, 0, 3) + + case AFADDS: + return FPOP2S(0, 0, 0, 2) + + case AFADDD: + return FPOP2S(0, 0, 1, 2) + + case AFSUBS: + return FPOP2S(0, 0, 0, 3) + + case AFSUBD: + return FPOP2S(0, 0, 1, 3) + + case AFMULS: + return FPOP2S(0, 0, 0, 0) + + case AFMULD: + return FPOP2S(0, 0, 1, 0) + + case AFDIVS: + return FPOP2S(0, 0, 0, 1) + + case AFDIVD: + return FPOP2S(0, 0, 1, 1) + + case AFMAXS: + return FPOP2S(0, 0, 0, 4) + + case AFMINS: + return FPOP2S(0, 0, 0, 5) + + case AFMAXD: + return FPOP2S(0, 0, 1, 4) + + case AFMIND: + return FPOP2S(0, 0, 1, 5) + + case AFMAXNMS: + return FPOP2S(0, 0, 0, 6) + + case AFMAXNMD: + return FPOP2S(0, 0, 1, 6) + + case AFMINNMS: + return FPOP2S(0, 0, 0, 7) + + case AFMINNMD: + return FPOP2S(0, 0, 1, 7) + + case AFNMULS: + return FPOP2S(0, 0, 0, 8) + + case AFNMULD: + return FPOP2S(0, 0, 1, 8) + + case AFCMPS: + return FPCMP(0, 0, 0, 0, 0) + + case AFCMPD: + return FPCMP(0, 0, 1, 0, 0) + + case AFCMPES: + return FPCMP(0, 0, 0, 0, 16) + + case AFCMPED: + return FPCMP(0, 0, 1, 0, 16) + + case AFCCMPS: + return FPCCMP(0, 0, 0, 0) + + case AFCCMPD: + return FPCCMP(0, 0, 1, 0) + + case AFCCMPES: + return FPCCMP(0, 0, 0, 1) + + case AFCCMPED: + return FPCCMP(0, 0, 1, 1) + + case AFCSELS: + return 0x1E<<24 | 0<<22 | 1<<21 | 3<<10 + + case AFCSELD: + return 0x1E<<24 | 1<<22 | 1<<21 | 3<<10 + + case AFMOVS: + return FPOP1S(0, 0, 0, 0) + + case AFABSS: + return FPOP1S(0, 0, 0, 1) + + case AFNEGS: + return FPOP1S(0, 0, 0, 2) + + case AFSQRTS: + return FPOP1S(0, 0, 0, 3) + + case AFCVTSD: + return FPOP1S(0, 0, 0, 5) + + case AFCVTSH: + return FPOP1S(0, 0, 0, 7) + + case AFRINTNS: + return FPOP1S(0, 0, 0, 8) + + case AFRINTPS: + return FPOP1S(0, 0, 0, 9) + + case AFRINTMS: + return FPOP1S(0, 0, 0, 10) + + case AFRINTZS: + return FPOP1S(0, 0, 0, 11) + + case AFRINTAS: + return FPOP1S(0, 0, 0, 12) + + case AFRINTXS: + return FPOP1S(0, 0, 0, 14) + + case AFRINTIS: + return FPOP1S(0, 0, 0, 15) + + case AFMOVD: + return FPOP1S(0, 0, 1, 0) + + case AFABSD: + return FPOP1S(0, 0, 1, 1) + + case AFNEGD: + return FPOP1S(0, 0, 1, 2) + + case AFSQRTD: + return FPOP1S(0, 0, 1, 3) + + case AFCVTDS: + return FPOP1S(0, 0, 1, 4) + + case AFCVTDH: + return FPOP1S(0, 0, 1, 7) + + case AFRINTND: + return FPOP1S(0, 0, 1, 8) + + case AFRINTPD: + return FPOP1S(0, 0, 1, 9) + + case AFRINTMD: + return FPOP1S(0, 0, 1, 10) + + case AFRINTZD: + return FPOP1S(0, 0, 1, 11) + + case AFRINTAD: + return FPOP1S(0, 0, 1, 12) + + case AFRINTXD: + return FPOP1S(0, 0, 1, 14) + + case AFRINTID: + return FPOP1S(0, 0, 1, 15) + + case AFCVTHS: + return FPOP1S(0, 0, 3, 4) + + case AFCVTHD: + return FPOP1S(0, 0, 3, 5) + } + + ctxt.Diag("bad rrr %d %v", a, obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +/* + * imm -> Rd + * imm op Rn -> Rd + */ +func opirr(ctxt *obj.Link, a int) uint32 { + switch a { + /* op $addcon, Rn, Rd */ + case AMOVD, + AADD: + return S64 | 0<<30 | 0<<29 | 0x11<<24 + + case ACMN, + AADDS: + return S64 | 0<<30 | 1<<29 | 0x11<<24 + + case AMOVW, + AADDW: + return S32 | 0<<30 | 0<<29 | 0x11<<24 + + case ACMNW, + AADDSW: + return S32 | 0<<30 | 1<<29 | 0x11<<24 + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x11<<24 + + case ACMP, + ASUBS: + return S64 | 1<<30 | 1<<29 | 0x11<<24 + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x11<<24 + + case ACMPW, + ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x11<<24 + + /* op $imm(SB), Rd; op label, Rd */ + case AADR: + return 0<<31 | 0x10<<24 + + case AADRP: + return 1<<31 | 0x10<<24 + + /* op $bimm, Rn, Rd */ + case AAND: + return S64 | 0<<29 | 0x24<<23 + + case AANDW: + return S32 | 0<<29 | 0x24<<23 | 0<<22 + + case AORR: + return S64 | 1<<29 | 0x24<<23 + + case AORRW: + return S32 | 1<<29 | 0x24<<23 | 0<<22 + + case AEOR: + return S64 | 2<<29 | 0x24<<23 + + case AEORW: + return S32 | 2<<29 | 0x24<<23 | 0<<22 + + case AANDS: + return S64 | 3<<29 | 0x24<<23 + + case AANDSW: + return S32 | 3<<29 | 0x24<<23 | 0<<22 + + case AASR: + return S64 | 0<<29 | 0x26<<23 /* alias of SBFM */ + + case AASRW: + return S32 | 0<<29 | 0x26<<23 | 0<<22 + + /* op $width, $lsb, Rn, Rd */ + case ABFI: + return S64 | 2<<29 | 0x26<<23 | 1<<22 + /* alias of BFM */ + + case ABFIW: + return S32 | 2<<29 | 0x26<<23 | 0<<22 + + /* op $imms, $immr, Rn, Rd */ + case ABFM: + return S64 | 1<<29 | 0x26<<23 | 1<<22 + + case ABFMW: + return S32 | 1<<29 | 0x26<<23 | 0<<22 + + case ASBFM: + return S64 | 0<<29 | 0x26<<23 | 1<<22 + + case ASBFMW: + return S32 | 0<<29 | 0x26<<23 | 0<<22 + + case AUBFM: + return S64 | 2<<29 | 0x26<<23 | 1<<22 + + case AUBFMW: + return S32 | 2<<29 | 0x26<<23 | 0<<22 + + case ABFXIL: + return S64 | 1<<29 | 0x26<<23 | 1<<22 /* alias of BFM */ + + case ABFXILW: + return S32 | 1<<29 | 0x26<<23 | 0<<22 + + case AEXTR: + return S64 | 0<<29 | 0x27<<23 | 1<<22 | 0<<21 + + case AEXTRW: + return S32 | 0<<29 | 0x27<<23 | 0<<22 | 0<<21 + + case ACBNZ: + return S64 | 0x1A<<25 | 1<<24 + + case ACBNZW: + return S32 | 0x1A<<25 | 1<<24 + + case ACBZ: + return S64 | 0x1A<<25 | 0<<24 + + case ACBZW: + return S32 | 0x1A<<25 | 0<<24 + + case ACCMN: + return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMNW: + return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 + + case ACCMP: + return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */ + + case ACCMPW: + return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 + + case AMOVK: + return S64 | 3<<29 | 0x25<<23 + + case AMOVKW: + return S32 | 3<<29 | 0x25<<23 + + case AMOVN: + return S64 | 0<<29 | 0x25<<23 + + case AMOVNW: + return S32 | 0<<29 | 0x25<<23 + + case AMOVZ: + return S64 | 2<<29 | 0x25<<23 + + case AMOVZW: + return S32 | 2<<29 | 0x25<<23 + + case AMSR: + return SYSOP(0, 0, 0, 4, 0, 0, 0x1F) /* MSR (immediate) */ + + case AAT, + ADC, + AIC, + ATLBI, + ASYS: + return SYSOP(0, 1, 0, 0, 0, 0, 0) + + case ASYSL: + return SYSOP(1, 1, 0, 0, 0, 0, 0) + + case ATBZ: + return 0x36 << 24 + + case ATBNZ: + return 0x37 << 24 + + case ADSB: + return SYSOP(0, 0, 3, 3, 0, 4, 0x1F) + + case ADMB: + return SYSOP(0, 0, 3, 3, 0, 5, 0x1F) + + case AISB: + return SYSOP(0, 0, 3, 3, 0, 6, 0x1F) + + case AHINT: + return SYSOP(0, 0, 3, 2, 0, 0, 0x1F) + } + + ctxt.Diag("bad irr %v", obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +func opbit(ctxt *obj.Link, a int) uint32 { + switch a { + case ACLS: + return S64 | OPBIT(5) + + case ACLSW: + return S32 | OPBIT(5) + + case ACLZ: + return S64 | OPBIT(4) + + case ACLZW: + return S32 | OPBIT(4) + + case ARBIT: + return S64 | OPBIT(0) + + case ARBITW: + return S32 | OPBIT(0) + + case AREV: + return S64 | OPBIT(3) + + case AREVW: + return S32 | OPBIT(2) + + case AREV16: + return S64 | OPBIT(1) + + case AREV16W: + return S32 | OPBIT(1) + + case AREV32: + return S64 | OPBIT(2) + + default: + ctxt.Diag("bad bit op\n%v", ctxt.Curp) + return 0 + } +} + +/* + * add/subtract extended register + */ +func opxrrr(ctxt *obj.Link, a int) uint32 { + switch a { + case AADD: + return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64 + + case AADDW: + return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32 + + case ACMN, + AADDS: + return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64 + + case ACMNW, + AADDSW: + return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32 + + case ASUB: + return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64 + + case ASUBW: + return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32 + + case ACMP, + ASUBS: + return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64 + + case ACMPW, + ASUBSW: + return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32 + } + + ctxt.Diag("bad opxrrr %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +func opimm(ctxt *obj.Link, a int) uint32 { + switch a { + case ASVC: + return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */ + + case AHVC: + return 0xD4<<24 | 0<<21 | 2 + + case ASMC: + return 0xD4<<24 | 0<<21 | 3 + + case ABRK: + return 0xD4<<24 | 1<<21 | 0 + + case AHLT: + return 0xD4<<24 | 2<<21 | 0 + + case ADCPS1: + return 0xD4<<24 | 5<<21 | 1 + + case ADCPS2: + return 0xD4<<24 | 5<<21 | 2 + + case ADCPS3: + return 0xD4<<24 | 5<<21 | 3 + + case ACLREX: + return SYSOP(0, 0, 3, 3, 0, 2, 0x1F) + } + + ctxt.Diag("bad imm %v", obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +func brdist(ctxt *obj.Link, p *obj.Prog, preshift int, flen int, shift int) int64 { + v := int64(0) + t := int64(0) + if p.Pcond != nil { + v = (p.Pcond.Pc >> uint(preshift)) - (ctxt.Pc >> uint(preshift)) + if (v & ((1 << uint(shift)) - 1)) != 0 { + ctxt.Diag("misaligned label\n%v", p) + } + v >>= uint(shift) + t = int64(1) << uint(flen-1) + if v < -t || v >= t { + ctxt.Diag("branch too far\n%v", p) + } + } + + return v & ((t << 1) - 1) +} + +/* + * pc-relative branches + */ +func opbra(ctxt *obj.Link, a int) uint32 { + switch a { + case ABEQ: + return OPBcc(0x0) + + case ABNE: + return OPBcc(0x1) + + case ABCS: + return OPBcc(0x2) + + case ABHS: + return OPBcc(0x2) + + case ABCC: + return OPBcc(0x3) + + case ABLO: + return OPBcc(0x3) + + case ABMI: + return OPBcc(0x4) + + case ABPL: + return OPBcc(0x5) + + case ABVS: + return OPBcc(0x6) + + case ABVC: + return OPBcc(0x7) + + case ABHI: + return OPBcc(0x8) + + case ABLS: + return OPBcc(0x9) + + case ABGE: + return OPBcc(0xa) + + case ABLT: + return OPBcc(0xb) + + case ABGT: + return OPBcc(0xc) + + case ABLE: + return OPBcc(0xd) /* imm19<<5 | cond */ + + case AB: + return 0<<31 | 5<<26 /* imm26 */ + + case obj.ADUFFZERO, + ABL: + return 1<<31 | 5<<26 + } + + ctxt.Diag("bad bra %v", obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +func opbrr(ctxt *obj.Link, a int) uint32 { + switch a { + case ABL: + return OPBLR(1) /* BLR */ + + case AB: + return OPBLR(0) /* BR */ + + case obj.ARET: + return OPBLR(2) /* RET */ + } + + ctxt.Diag("bad brr %v", obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +func op0(ctxt *obj.Link, a int) uint32 { + switch a { + case ADRPS: + return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5 + + case AERET: + return 0x6B<<25 | 4<<21 | 0x1F<<16 | 0<<10 | 0x1F<<5 + + // case ANOP: + // return SYSHINT(0) + + case AYIELD: + return SYSHINT(1) + + case AWFE: + return SYSHINT(2) + + case AWFI: + return SYSHINT(3) + + case ASEV: + return SYSHINT(4) + + case ASEVL: + return SYSHINT(5) + } + + ctxt.Diag("bad op0 %v", obj.Aconv(a)) + prasm(ctxt.Curp) + return 0 +} + +/* + * register offset + */ +func opload(ctxt *obj.Link, a int) uint32 { + switch a { + case ALDAR: + return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARW: + return LDSTX(2, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARB: + return LDSTX(0, 1, 1, 0, 1) | 0x1F<<10 + + case ALDARH: + return LDSTX(1, 1, 1, 0, 1) | 0x1F<<10 + + case ALDAXP: + return LDSTX(3, 0, 1, 1, 1) + + case ALDAXPW: + return LDSTX(2, 0, 1, 1, 1) + + case ALDAXR: + return LDSTX(3, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRW: + return LDSTX(2, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRB: + return LDSTX(0, 0, 1, 0, 1) | 0x1F<<10 + + case ALDAXRH: + return LDSTX(1, 0, 1, 0, 1) | 0x1F<<10 + + case ALDXR: + return LDSTX(3, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRB: + return LDSTX(0, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRH: + return LDSTX(1, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXRW: + return LDSTX(2, 0, 1, 0, 0) | 0x1F<<10 + + case ALDXP: + return LDSTX(3, 0, 1, 1, 0) + + case ALDXPW: + return LDSTX(2, 0, 1, 1, 0) + + case AMOVNP: + return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + + case AMOVNPW: + return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + } + + ctxt.Diag("bad opload %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +func opstore(ctxt *obj.Link, a int) uint32 { + switch a { + case ASTLR: + return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLRB: + return LDSTX(0, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLRH: + return LDSTX(1, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLP: + return LDSTX(3, 0, 0, 1, 1) + + case ASTLPW: + return LDSTX(2, 0, 0, 1, 1) + + case ASTLRW: + return LDSTX(2, 1, 0, 0, 1) | 0x1F<<10 + + case ASTLXP: + return LDSTX(2, 0, 0, 1, 1) + + case ASTLXPW: + return LDSTX(3, 0, 0, 1, 1) + + case ASTLXR: + return LDSTX(3, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRB: + return LDSTX(0, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRH: + return LDSTX(1, 0, 0, 0, 1) | 0x1F<<10 + + case ASTLXRW: + return LDSTX(2, 0, 0, 0, 1) | 0x1F<<10 + + case ASTXR: + return LDSTX(3, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXRB: + return LDSTX(0, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXRH: + return LDSTX(1, 0, 0, 0, 0) | 0x1F<<10 + + case ASTXP: + return LDSTX(3, 0, 0, 1, 0) + + case ASTXPW: + return LDSTX(2, 0, 0, 1, 0) + + case ASTXRW: + return LDSTX(2, 0, 0, 0, 0) | 0x1F<<10 + + case AMOVNP: + return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + + case AMOVNPW: + return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22 + } + + ctxt.Diag("bad opstore %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +/* + * load/store register (unsigned immediate) C3.3.13 + * these produce 64-bit values (when there's an option) + */ +func olsr12u(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 { + if v < 0 || v >= (1<<12) { + ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp) + } + o |= (v & 0xFFF) << 10 + o |= int32(b&31) << 5 + o |= int32(r & 31) + return uint32(o) +} + +func opldr12(ctxt *obj.Link, a int) uint32 { + switch a { + case AMOVD: + return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */ + + case AMOVW: + return LDSTR12U(2, 0, 2) + + case AMOVWU: + return LDSTR12U(2, 0, 1) + + case AMOVH: + return LDSTR12U(1, 0, 2) + + case AMOVHU: + return LDSTR12U(1, 0, 1) + + case AMOVB: + return LDSTR12U(0, 0, 2) + + case AMOVBU: + return LDSTR12U(0, 0, 1) + + case AFMOVS: + return LDSTR12U(2, 1, 1) + + case AFMOVD: + return LDSTR12U(3, 1, 1) + } + + ctxt.Diag("bad opldr12 %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +func opstr12(ctxt *obj.Link, a int) uint32 { + return LD2STR(opldr12(ctxt, a)) +} + +/* + * load/store register (unscaled immediate) C3.3.12 + */ +func olsr9s(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 { + if v < -256 || v > 255 { + ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp) + } + o |= (v & 0x1FF) << 12 + o |= int32(b&31) << 5 + o |= int32(r & 31) + return uint32(o) +} + +func opldr9(ctxt *obj.Link, a int) uint32 { + switch a { + case AMOVD: + return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */ + + case AMOVW: + return LDSTR9S(2, 0, 2) + + case AMOVWU: + return LDSTR9S(2, 0, 1) + + case AMOVH: + return LDSTR9S(1, 0, 2) + + case AMOVHU: + return LDSTR9S(1, 0, 1) + + case AMOVB: + return LDSTR9S(0, 0, 2) + + case AMOVBU: + return LDSTR9S(0, 0, 1) + + case AFMOVS: + return LDSTR9S(2, 1, 1) + + case AFMOVD: + return LDSTR9S(3, 1, 1) + } + + ctxt.Diag("bad opldr9 %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +func opstr9(ctxt *obj.Link, a int) uint32 { + return LD2STR(opldr9(ctxt, a)) +} + +func opldrpp(ctxt *obj.Link, a int) uint32 { + switch a { + case AMOVD: + return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */ + + case AMOVW: + return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVWU: + return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + + case AMOVH: + return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVHU: + return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + + case AMOVB: + return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22 + + case AMOVBU: + return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 + } + + ctxt.Diag("bad opldr %v\n%v", obj.Aconv(a), ctxt.Curp) + return 0 +} + +/* + * load/store register (extended register) + */ +func olsxrr(ctxt *obj.Link, as int, rt int, r1 int, r2 int) uint32 { + ctxt.Diag("need load/store extended register\n%v", ctxt.Curp) + return 0xffffffff +} + +func oaddi(ctxt *obj.Link, o1 int32, v int32, r int, rt int) uint32 { + if (v & 0xFFF000) != 0 { + if v&0xFFF != 0 { + ctxt.Diag("%v misuses oaddi", ctxt.Curp) + } + v >>= 12 + o1 |= 1 << 22 + } + + o1 |= ((v & 0xFFF) << 10) | (int32(r&31) << 5) | int32(rt&31) + return uint32(o1) +} + +/* + * load a a literal value into dr + */ +func omovlit(ctxt *obj.Link, as int, p *obj.Prog, a *obj.Addr, dr int) uint32 { + var o1 int32 + if p.Pcond == nil { /* not in literal pool */ + aclass(ctxt, a) + fmt.Fprintf(ctxt.Bso, "omovlit add %d (%#x)\n", ctxt.Instoffset, uint64(ctxt.Instoffset)) + + /* TODO: could be clever, and use general constant builder */ + o1 = int32(opirr(ctxt, AADD)) + + v := int32(ctxt.Instoffset) + if v != 0 && (v&0xFFF) == 0 { + v >>= 12 + o1 |= 1 << 22 /* shift, by 12 */ + } + + o1 |= ((v & 0xFFF) << 10) | (REGZERO & 31 << 5) | int32(dr&31) + } else { + fp := 0 + w := 0 /* default: 32 bit, unsigned */ + switch as { + case AFMOVS: + fp = 1 + + case AFMOVD: + fp = 1 + w = 1 /* 64 bit simd&fp */ + + case AMOVD: + if p.Pcond.As == ADWORD { + w = 1 /* 64 bit */ + } else if p.Pcond.To.Offset < 0 { + w = 2 /* sign extend */ + } + + case AMOVB, + AMOVH, + AMOVW: + w = 2 /* 32 bit, sign-extended to 64 */ + break + } + + v := int32(brdist(ctxt, p, 0, 19, 2)) + o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27) + o1 |= (v & 0x7FFFF) << 5 + o1 |= int32(dr & 31) + } + + return uint32(o1) +} + +func opbfm(ctxt *obj.Link, a int, r int, s int, rf int, rt int) uint32 { + var c uint32 + o := opirr(ctxt, a) + if (o & (1 << 31)) == 0 { + c = 32 + } else { + c = 64 + } + if r < 0 || uint32(r) >= c { + ctxt.Diag("illegal bit number\n%v", ctxt.Curp) + } + o |= (uint32(r) & 0x3F) << 16 + if s < 0 || uint32(s) >= c { + ctxt.Diag("illegal bit number\n%v", ctxt.Curp) + } + o |= (uint32(s) & 0x3F) << 10 + o |= (uint32(rf&31) << 5) | uint32(rt&31) + return o +} + +func opextr(ctxt *obj.Link, a int, v int32, rn int, rm int, rt int) uint32 { + var c uint32 + o := opirr(ctxt, a) + if (o & (1 << 31)) != 0 { + c = 63 + } else { + c = 31 + } + if v < 0 || uint32(v) > c { + ctxt.Diag("illegal bit number\n%v", ctxt.Curp) + } + o |= uint32(v) << 10 + o |= uint32(rn&31) << 5 + o |= uint32(rm&31) << 16 + o |= uint32(rt & 31) + return o +} + +/* + * size in log2(bytes) + */ +func movesize(a int) int { + switch a { + case AMOVD: + return 3 + + case AMOVW, + AMOVWU: + return 2 + + case AMOVH, + AMOVHU: + return 1 + + case AMOVB, + AMOVBU: + return 0 + + case AFMOVS: + return 2 + + case AFMOVD: + return 3 + + default: + return -1 + } +} diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go new file mode 100644 index 0000000000..53d67c91bb --- /dev/null +++ b/src/cmd/internal/obj/arm64/list7.go @@ -0,0 +1,114 @@ +// cmd/7l/list.c and cmd/7l/sub.c from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/ +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import ( + "cmd/internal/obj" + "fmt" +) + +var strcond = [16]string{ + "EQ", + "NE", + "HS", + "LO", + "MI", + "PL", + "VS", + "VC", + "HI", + "LS", + "GE", + "LT", + "GT", + "LE", + "AL", + "NV", +} + +func init() { + obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, Rconv) + obj.RegisterOpcode(obj.ABaseARM64, Anames) +} + +func Rconv(r int) string { + if r == REGG { + return "g" + } + switch { + case REG_R0 <= r && r <= REG_R30: + return fmt.Sprintf("R%d", r-REG_R0) + case r == REG_R31: + return "ZR" + case REG_F0 <= r && r <= REG_F31: + return fmt.Sprintf("F%d", r-REG_F0) + case REG_V0 <= r && r <= REG_V31: + return fmt.Sprintf("V%d", r-REG_F0) + case COND_EQ <= r && r <= COND_NV: + return strcond[r-COND_EQ] + case r == REGSP: + return "RSP" + case r == REG_DAIF: + return "DAIF" + case r == REG_NZCV: + return "NZCV" + case r == REG_FPSR: + return "FPSR" + case r == REG_FPCR: + return "FPCR" + case r == REG_SPSR_EL1: + return "SPSR_EL1" + case r == REG_ELR_EL1: + return "ELR_EL1" + case r == REG_SPSR_EL2: + return "SPSR_EL2" + case r == REG_ELR_EL2: + return "ELR_EL2" + case r == REG_CurrentEL: + return "CurrentEL" + case r == REG_SP_EL0: + return "SP_EL0" + case r == REG_SPSel: + return "SPSel" + case r == REG_DAIFSet: + return "DAIFSet" + case r == REG_DAIFClr: + return "DAIFClr" + } + return fmt.Sprintf("badreg(%d)", r) +} + +func DRconv(a int) string { + if a >= C_NONE && a <= C_NCLASS { + return cnames7[a] + } + return "C_??" +} diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go new file mode 100644 index 0000000000..0b92cfcaf1 --- /dev/null +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -0,0 +1,829 @@ +// cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova. +// https://code.google.com/p/ken-cc/source/browse/ +// +// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. +// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) +// Portions Copyright © 1997-1999 Vita Nuova Limited +// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) +// Portions Copyright © 2004,2006 Bruce Ellis +// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) +// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others +// Portions Copyright © 2009 The Go Authors. All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package arm64 + +import ( + "cmd/internal/obj" + "encoding/binary" + "fmt" + "log" + "math" +) + +var complements = []int16{ + AADD: ASUB, + AADDW: ASUBW, + ASUB: AADD, + ASUBW: AADDW, + ACMP: ACMN, + ACMPW: ACMNW, + ACMN: ACMP, + ACMNW: ACMPW, +} + +func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt int) *obj.Prog { + // MOV g_stackguard(g), R1 + p = obj.Appendp(ctxt, p) + + p.As = AMOVD + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGG + p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0 + if ctxt.Cursym.Cfunc != 0 { + p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1 + } + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R1 + + q := (*obj.Prog)(nil) + if framesize <= obj.StackSmall { + // small stack: SP < stackguard + // MOV SP, R2 + // CMP stackguard, R2 + p = obj.Appendp(ctxt, p) + + p.As = AMOVD + p.From.Type = obj.TYPE_REG + p.From.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + + p = obj.Appendp(ctxt, p) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.Reg = REG_R2 + } else if framesize <= obj.StackBig { + // large stack: SP-framesize < stackguard-StackSmall + // SUB $framesize, SP, R2 + // CMP stackguard, R2 + p = obj.Appendp(ctxt, p) + + p.As = ASUB + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(framesize) + p.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + + p = obj.Appendp(ctxt, p) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.Reg = REG_R2 + } else { + // Such a large stack we need to protect against wraparound + // if SP is close to zero. + // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) + // The +StackGuard on both sides is required to keep the left side positive: + // SP is allowed to be slightly below stackguard. See stack.h. + // CMP $StackPreempt, R1 + // BEQ label_of_call_to_morestack + // ADD $StackGuard, SP, R2 + // SUB R1, R2 + // MOV $(framesize+(StackGuard-StackSmall)), R3 + // CMP R3, R2 + p = obj.Appendp(ctxt, p) + + p.As = ACMP + p.From.Type = obj.TYPE_CONST + p.From.Offset = obj.StackPreempt + p.Reg = REG_R1 + + p = obj.Appendp(ctxt, p) + q = p + p.As = ABEQ + p.To.Type = obj.TYPE_BRANCH + + p = obj.Appendp(ctxt, p) + p.As = AADD + p.From.Type = obj.TYPE_CONST + p.From.Offset = obj.StackGuard + p.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + + p = obj.Appendp(ctxt, p) + p.As = ASUB + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R1 + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R2 + + p = obj.Appendp(ctxt, p) + p.As = AMOVD + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall) + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R3 + + p = obj.Appendp(ctxt, p) + p.As = ACMP + p.From.Type = obj.TYPE_REG + p.From.Reg = REG_R3 + p.Reg = REG_R2 + } + + // BHI done + p = obj.Appendp(ctxt, p) + q1 := p + + p.As = ABHI + p.To.Type = obj.TYPE_BRANCH + + // MOV LR, R3 + p = obj.Appendp(ctxt, p) + + p.As = AMOVD + p.From.Type = obj.TYPE_REG + p.From.Reg = REGLINK + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R3 + if q != nil { + q.Pcond = p + } + + // TODO(minux): only for debug + p = obj.Appendp(ctxt, p) + p.As = AMOVD + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(framesize) + p.To.Type = obj.TYPE_REG + p.To.Reg = REGTMP + + // BL runtime.morestack(SB) + p = obj.Appendp(ctxt, p) + + p.As = ABL + p.To.Type = obj.TYPE_BRANCH + if ctxt.Cursym.Cfunc != 0 { + p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0) + } else { + p.To.Sym = ctxt.Symmorestack[noctxt] + } + + // B start + p = obj.Appendp(ctxt, p) + + p.As = AB + p.To.Type = obj.TYPE_BRANCH + p.Pcond = ctxt.Cursym.Text.Link + + // placeholder for q1's jump target + p = obj.Appendp(ctxt, p) + + p.As = obj.ANOP + q1.Pcond = p + + return p +} + +func progedit(ctxt *obj.Link, p *obj.Prog) { + p.From.Class = 0 + p.To.Class = 0 + + // $0 results in C_ZCON, which matches both C_REG and various + // C_xCON, however the C_REG cases in asmout don't expect a + // constant, so they will use the register fields and assemble + // a R0. To prevent that, rewrite $0 as ZR. + if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 { + p.From.Type = obj.TYPE_REG + p.From.Reg = REGZERO + } + if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 { + p.To.Type = obj.TYPE_REG + p.To.Reg = REGZERO + } + + // Rewrite BR/BL to symbol as TYPE_BRANCH. + switch p.As { + case AB, + ABL, + obj.ARET, + obj.ADUFFZERO, + obj.ADUFFCOPY: + if p.To.Sym != nil { + p.To.Type = obj.TYPE_BRANCH + } + break + } + + // Rewrite float constants to values stored in memory. + switch p.As { + case AFMOVS: + if p.From.Type == obj.TYPE_FCONST { + f32 := float32(p.From.U.Dval) + i32 := math.Float32bits(f32) + literal := fmt.Sprintf("$f32.%08x", uint32(i32)) + s := obj.Linklookup(ctxt, literal, 0) + s.Size = 4 + p.From.Type = obj.TYPE_MEM + p.From.Sym = s + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } + + case AFMOVD: + if p.From.Type == obj.TYPE_FCONST { + i64 := math.Float64bits(p.From.U.Dval) + literal := fmt.Sprintf("$f64.%016x", uint64(i64)) + s := obj.Linklookup(ctxt, literal, 0) + s.Size = 8 + p.From.Type = obj.TYPE_MEM + p.From.Sym = s + p.From.Name = obj.NAME_EXTERN + p.From.Offset = 0 + } + + break + } + + // Rewrite negative immediates as positive immediates with + // complementary instruction. + switch p.As { + case AADD, + AADDW, + ASUB, + ASUBW, + ACMP, + ACMPW, + ACMN, + ACMNW: + if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 { + p.From.Offset = -p.From.Offset + p.As = complements[p.As] + } + + break + } +} + +func follow(ctxt *obj.Link, s *obj.LSym) { + ctxt.Cursym = s + + firstp := ctxt.NewProg() + lastp := firstp + xfol(ctxt, s.Text, &lastp) + lastp.Link = nil + s.Text = firstp.Link +} + +func relinv(a int) int { + switch a { + case ABEQ: + return ABNE + case ABNE: + return ABEQ + case ABCS: + return ABCC + case ABHS: + return ABLO + case ABCC: + return ABCS + case ABLO: + return ABHS + case ABMI: + return ABPL + case ABPL: + return ABMI + case ABVS: + return ABVC + case ABVC: + return ABVS + case ABHI: + return ABLS + case ABLS: + return ABHI + case ABGE: + return ABLT + case ABLT: + return ABGE + case ABGT: + return ABLE + case ABLE: + return ABGT + } + + log.Fatalf("unknown relation: %s", Anames[a]) + return 0 +} + +func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) { + var q *obj.Prog + var r *obj.Prog + var a int + var i int + +loop: + if p == nil { + return + } + a = int(p.As) + if a == AB { + q = p.Pcond + if q != nil { + p.Mark |= FOLL + p = q + if !(p.Mark&FOLL != 0) { + goto loop + } + } + } + + if p.Mark&FOLL != 0 { + i = 0 + q = p + for ; i < 4; (func() { i++; q = q.Link })() { + if q == *last || q == nil { + break + } + a = int(q.As) + if a == obj.ANOP { + i-- + continue + } + + if a == AB || a == obj.ARET || a == AERET { + goto copy + } + if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) { + continue + } + if a != ABEQ && a != ABNE { + continue + } + + copy: + for { + r = ctxt.NewProg() + *r = *p + if !(r.Mark&FOLL != 0) { + fmt.Printf("cant happen 1\n") + } + r.Mark |= FOLL + if p != q { + p = p.Link + (*last).Link = r + *last = r + continue + } + + (*last).Link = r + *last = r + if a == AB || a == obj.ARET || a == AERET { + return + } + if a == ABNE { + r.As = ABEQ + } else { + r.As = ABNE + } + r.Pcond = p.Link + r.Link = p.Pcond + if !(r.Link.Mark&FOLL != 0) { + xfol(ctxt, r.Link, last) + } + if !(r.Pcond.Mark&FOLL != 0) { + fmt.Printf("cant happen 2\n") + } + return + } + } + + a = AB + q = ctxt.NewProg() + q.As = int16(a) + q.Lineno = p.Lineno + q.To.Type = obj.TYPE_BRANCH + q.To.Offset = p.Pc + q.Pcond = p + p = q + } + + p.Mark |= FOLL + (*last).Link = p + *last = p + if a == AB || a == obj.ARET || a == AERET { + return + } + if p.Pcond != nil { + if a != ABL && p.Link != nil { + q = obj.Brchain(ctxt, p.Link) + if a != obj.ATEXT && a != ABCASE { + if q != nil && (q.Mark&FOLL != 0) { + p.As = int16(relinv(a)) + p.Link = p.Pcond + p.Pcond = q + } + } + + xfol(ctxt, p.Link, last) + q = obj.Brchain(ctxt, p.Pcond) + if q == nil { + q = p.Pcond + } + if q.Mark&FOLL != 0 { + p.Pcond = q + return + } + + p = q + goto loop + } + } + + p = p.Link + goto loop +} + +func preprocess(ctxt *obj.Link, cursym *obj.LSym) { + if ctxt.Symmorestack[0] == nil { + ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0) + ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0) + } + + ctxt.Cursym = cursym + + if cursym.Text == nil || cursym.Text.Link == nil { + return + } + + p := cursym.Text + textstksiz := p.To.Offset + aoffset := int32(textstksiz) + + cursym.Args = p.To.U.Argsize + cursym.Locals = int32(textstksiz) + + /* + * find leaf subroutines + * strip NOPs + * expand RET + */ + obj.Bflush(ctxt.Bso) + q := (*obj.Prog)(nil) + var q1 *obj.Prog + for p := cursym.Text; p != nil; p = p.Link { + switch p.As { + case obj.ATEXT: + p.Mark |= LEAF + + case obj.ARET: + break + + case obj.ANOP: + q1 = p.Link + q.Link = q1 /* q is non-nop */ + q1.Mark |= p.Mark + continue + + case ABL, + obj.ADUFFZERO, + obj.ADUFFCOPY: + cursym.Text.Mark &^= LEAF + fallthrough + + case ACBNZ, + ACBZ, + ACBNZW, + ACBZW, + ATBZ, + ATBNZ, + ABCASE, + AB, + ABEQ, + ABNE, + ABCS, + ABHS, + ABCC, + ABLO, + ABMI, + ABPL, + ABVS, + ABVC, + ABHI, + ABLS, + ABGE, + ABLT, + ABGT, + ABLE, + AADR, /* strange */ + AADRP: + q1 = p.Pcond + + if q1 != nil { + for q1.As == obj.ANOP { + q1 = q1.Link + p.Pcond = q1 + } + } + + break + } + + q = p + } + + var o int + var q2 *obj.Prog + var retjmp *obj.LSym + var stkadj int64 + for p := cursym.Text; p != nil; p = p.Link { + o = int(p.As) + switch o { + case obj.ATEXT: + cursym.Text = p + if textstksiz < 0 { + ctxt.Autosize = 0 + } else { + ctxt.Autosize = int32(textstksiz + 8) + } + if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 { + ctxt.Autosize = 0 + } else if ctxt.Autosize&(16-1) != 0 { + stkadj = 16 - (int64(ctxt.Autosize) & (16 - 1)) + ctxt.Autosize += int32(stkadj) + cursym.Locals += int32(stkadj) + } + p.To.Offset = int64(ctxt.Autosize) - 8 + if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) { + if ctxt.Debugvlog != 0 { + fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name) + } + obj.Bflush(ctxt.Bso) + cursym.Text.Mark |= LEAF + } + + if !(p.From3.Offset&obj.NOSPLIT != 0) { + p = stacksplit(ctxt, p, ctxt.Autosize, bool2int(cursym.Text.From3.Offset&obj.NEEDCTXT == 0)) // emit split check + } + + aoffset = ctxt.Autosize + if aoffset > 0xF0 { + aoffset = 0xF0 + } + if cursym.Text.Mark&LEAF != 0 { + cursym.Leaf = 1 + if ctxt.Autosize == 0 { + break + } + aoffset = 0 + } + + q = p + if ctxt.Autosize > aoffset { + q = ctxt.NewProg() + q.As = ASUB + q.Lineno = p.Lineno + q.From.Type = obj.TYPE_CONST + q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) + q.To.Type = obj.TYPE_REG + q.To.Reg = REGSP + q.Spadj = int32(q.From.Offset) + q.Link = p.Link + p.Link = q + if cursym.Text.Mark&LEAF != 0 { + break + } + } + + q1 = ctxt.NewProg() + q1.As = AMOVD + q1.Lineno = p.Lineno + q1.From.Type = obj.TYPE_REG + q1.From.Reg = REGLINK + q1.To.Type = obj.TYPE_MEM + q1.Scond = C_XPRE + q1.To.Offset = int64(-aoffset) + q1.To.Reg = REGSP + q1.Link = q.Link + q1.Spadj = aoffset + q.Link = q1 + + if cursym.Text.From3.Offset&obj.WRAPPER != 0 { + // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame + // + // MOV g_panic(g), R1 + // CMP ZR, R1 + // BEQ end + // MOV panic_argp(R1), R2 + // ADD $(autosize+8), RSP, R3 + // CMP R2, R3 + // BNE end + // ADD $8, RSP, R4 + // MOVD R4, panic_argp(R1) + // end: + // NOP + // + // The NOP is needed to give the jumps somewhere to land. + // It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes. + q = q1 + + q = obj.Appendp(ctxt, q) + q.As = AMOVD + q.From.Type = obj.TYPE_MEM + q.From.Reg = REGG + q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic + q.To.Type = obj.TYPE_REG + q.To.Reg = REG_R1 + + q = obj.Appendp(ctxt, q) + q.As = ACMP + q.From.Type = obj.TYPE_REG + q.From.Reg = REGZERO + q.Reg = REG_R1 + + q = obj.Appendp(ctxt, q) + q.As = ABEQ + q.To.Type = obj.TYPE_BRANCH + q1 = q + + q = obj.Appendp(ctxt, q) + q.As = AMOVD + q.From.Type = obj.TYPE_MEM + q.From.Reg = REG_R1 + q.From.Offset = 0 // Panic.argp + q.To.Type = obj.TYPE_REG + q.To.Reg = REG_R2 + + q = obj.Appendp(ctxt, q) + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = int64(ctxt.Autosize) + 8 + q.Reg = REGSP + q.To.Type = obj.TYPE_REG + q.To.Reg = REG_R3 + + q = obj.Appendp(ctxt, q) + q.As = ACMP + q.From.Type = obj.TYPE_REG + q.From.Reg = REG_R2 + q.Reg = REG_R3 + + q = obj.Appendp(ctxt, q) + q.As = ABNE + q.To.Type = obj.TYPE_BRANCH + q2 = q + + q = obj.Appendp(ctxt, q) + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = 8 + q.Reg = REGSP + q.To.Type = obj.TYPE_REG + q.To.Reg = REG_R4 + + q = obj.Appendp(ctxt, q) + q.As = AMOVD + q.From.Type = obj.TYPE_REG + q.From.Reg = REG_R4 + q.To.Type = obj.TYPE_MEM + q.To.Reg = REG_R1 + q.To.Offset = 0 // Panic.argp + + q = obj.Appendp(ctxt, q) + + q.As = obj.ANOP + q1.Pcond = q + q2.Pcond = q + } + + case obj.ARET: + nocache(p) + if p.From.Type == obj.TYPE_CONST { + ctxt.Diag("using BECOME (%v) is not supported!", p) + break + } + + retjmp = p.To.Sym + p.To = obj.Addr{} + if cursym.Text.Mark&LEAF != 0 { + if ctxt.Autosize != 0 { + p.As = AADD + p.From.Type = obj.TYPE_CONST + p.From.Offset = int64(ctxt.Autosize) + p.To.Type = obj.TYPE_REG + p.To.Reg = REGSP + p.Spadj = -ctxt.Autosize + } + } else { + /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ + aoffset = ctxt.Autosize + + if aoffset > 0xF0 { + aoffset = 0xF0 + } + p.As = AMOVD + p.From.Type = obj.TYPE_MEM + p.Scond = C_XPOST + p.From.Offset = int64(aoffset) + p.From.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REGLINK + p.Spadj = -aoffset + if ctxt.Autosize > aoffset { + q = ctxt.NewProg() + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = int64(ctxt.Autosize) - int64(aoffset) + q.To.Type = obj.TYPE_REG + q.To.Reg = REGSP + q.Link = p.Link + q.Spadj = int32(-q.From.Offset) + q.Lineno = p.Lineno + p.Link = q + p = q + } + } + + if p.As != obj.ARET { + q = ctxt.NewProg() + q.Lineno = p.Lineno + q.Link = p.Link + p.Link = q + p = q + } + + if retjmp != nil { // retjmp + p.As = AB + p.To.Type = obj.TYPE_BRANCH + p.To.Sym = retjmp + p.Spadj = +ctxt.Autosize + break + } + + p.As = obj.ARET + p.Lineno = p.Lineno + p.To.Type = obj.TYPE_MEM + p.To.Offset = 0 + p.To.Reg = REGLINK + p.Spadj = +ctxt.Autosize + + case AADD, + ASUB: + if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { + if p.As == AADD { + p.Spadj = int32(-p.From.Offset) + } else { + p.Spadj = int32(+p.From.Offset) + } + } + break + } + } +} + +func nocache(p *obj.Prog) { + p.Optab = 0 + p.From.Class = 0 + p.To.Class = 0 +} + +var unaryDst = map[int]bool{ + AWORD: true, + ADWORD: true, + ABL: true, + AB: true, +} + +var Linkarm64 = obj.LinkArch{ + ByteOrder: binary.LittleEndian, + Name: "arm64", + Thechar: '7', + Preprocess: preprocess, + Assemble: span7, + Follow: follow, + Progedit: progedit, + UnaryDst: unaryDst, + Minlc: 4, + Ptrsize: 8, + Regsize: 8, +} diff --git a/src/cmd/internal/obj/arm64/util.go b/src/cmd/internal/obj/arm64/util.go new file mode 100644 index 0000000000..7cb50404dc --- /dev/null +++ b/src/cmd/internal/obj/arm64/util.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package arm64 + +func bool2int(b bool) int { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 2151586cfb..ea38f54ebb 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -66,6 +66,7 @@ type Prog struct { Reg int16 From3 Addr To Addr + To2 Addr Opt interface{} Forwd *Prog Pcond *Prog @@ -505,6 +506,7 @@ const ( R_SIZE R_CALL R_CALLARM + R_CALLARM64 R_CALLIND R_CALLPOWER R_CONST diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index b2c7df7d56..a2f3c1f8f1 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -332,6 +332,9 @@ func (p *Prog) String() string { if p.To.Type != TYPE_NONE { fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) } + if p.To2.Type != TYPE_NONE { + fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To2)) + } return buf.String() } @@ -523,10 +526,8 @@ const ( RBase386 = 1 * 1024 RBaseAMD64 = 2 * 1024 RBaseARM = 3 * 1024 - RBasePPC64 = 4 * 1024 - // The next free base is 8*1024 (PPC64 has many registers). - // Alternatively, the next architecture, with an ordinary - // number of registers, could go under PPC64. + RBasePPC64 = 4 * 1024 // range [4k, 8k) + RBaseARM64 = 8 * 1024 // range [8k, 12k) ) // RegisterRegister binds a pretty-printer (Rconv) for register @@ -585,6 +586,7 @@ const ( ABaseARM ABaseAMD64 ABasePPC64 + ABaseARM64 AMask = 1<<12 - 1 // AND with this to use the opcode as an array index. )