summaryrefslogtreecommitdiff
path: root/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go')
-rw-r--r--vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go7140
1 files changed, 0 insertions, 7140 deletions
diff --git a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go b/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go
deleted file mode 100644
index 2bbb64b9d..000000000
--- a/vendor/github.com/twitchyliquid64/golang-asm/obj/arm64/asm7.go
+++ /dev/null
@@ -1,7140 +0,0 @@
-// 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 (
- "github.com/twitchyliquid64/golang-asm/obj"
- "github.com/twitchyliquid64/golang-asm/objabi"
- "fmt"
- "log"
- "math"
- "sort"
-)
-
-// ctxt7 holds state while assembling a single function.
-// Each function gets a fresh ctxt7.
-// This allows for multiple functions to be safely concurrently assembled.
-type ctxt7 struct {
- ctxt *obj.Link
- newprog obj.ProgAlloc
- cursym *obj.LSym
- blitrl *obj.Prog
- elitrl *obj.Prog
- autosize int32
- extrasize int32
- instoffset int64
- pc int64
- pool struct {
- start uint32
- size uint32
- }
-}
-
-const (
- funcAlign = 16
-)
-
-const (
- REGFROM = 1
-)
-
-type Optab struct {
- as obj.As
- a1 uint8
- a2 uint8
- a3 uint8
- a4 uint8
- type_ int8
- size int8
- param int16
- flag int8
- scond uint16
-}
-
-func IsAtomicInstruction(as obj.As) bool {
- _, ok := atomicInstructions[as]
- return ok
-}
-
-// known field values of an instruction.
-var atomicInstructions = map[obj.As]uint32{
- ALDADDAD: 3<<30 | 0x1c5<<21 | 0x00<<10,
- ALDADDAW: 2<<30 | 0x1c5<<21 | 0x00<<10,
- ALDADDAH: 1<<30 | 0x1c5<<21 | 0x00<<10,
- ALDADDAB: 0<<30 | 0x1c5<<21 | 0x00<<10,
- ALDADDALD: 3<<30 | 0x1c7<<21 | 0x00<<10,
- ALDADDALW: 2<<30 | 0x1c7<<21 | 0x00<<10,
- ALDADDALH: 1<<30 | 0x1c7<<21 | 0x00<<10,
- ALDADDALB: 0<<30 | 0x1c7<<21 | 0x00<<10,
- ALDADDD: 3<<30 | 0x1c1<<21 | 0x00<<10,
- ALDADDW: 2<<30 | 0x1c1<<21 | 0x00<<10,
- ALDADDH: 1<<30 | 0x1c1<<21 | 0x00<<10,
- ALDADDB: 0<<30 | 0x1c1<<21 | 0x00<<10,
- ALDADDLD: 3<<30 | 0x1c3<<21 | 0x00<<10,
- ALDADDLW: 2<<30 | 0x1c3<<21 | 0x00<<10,
- ALDADDLH: 1<<30 | 0x1c3<<21 | 0x00<<10,
- ALDADDLB: 0<<30 | 0x1c3<<21 | 0x00<<10,
- ALDANDAD: 3<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAW: 2<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAH: 1<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDAB: 0<<30 | 0x1c5<<21 | 0x04<<10,
- ALDANDALD: 3<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALW: 2<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALH: 1<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDALB: 0<<30 | 0x1c7<<21 | 0x04<<10,
- ALDANDD: 3<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDW: 2<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDH: 1<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDB: 0<<30 | 0x1c1<<21 | 0x04<<10,
- ALDANDLD: 3<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLW: 2<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLH: 1<<30 | 0x1c3<<21 | 0x04<<10,
- ALDANDLB: 0<<30 | 0x1c3<<21 | 0x04<<10,
- ALDEORAD: 3<<30 | 0x1c5<<21 | 0x08<<10,
- ALDEORAW: 2<<30 | 0x1c5<<21 | 0x08<<10,
- ALDEORAH: 1<<30 | 0x1c5<<21 | 0x08<<10,
- ALDEORAB: 0<<30 | 0x1c5<<21 | 0x08<<10,
- ALDEORALD: 3<<30 | 0x1c7<<21 | 0x08<<10,
- ALDEORALW: 2<<30 | 0x1c7<<21 | 0x08<<10,
- ALDEORALH: 1<<30 | 0x1c7<<21 | 0x08<<10,
- ALDEORALB: 0<<30 | 0x1c7<<21 | 0x08<<10,
- ALDEORD: 3<<30 | 0x1c1<<21 | 0x08<<10,
- ALDEORW: 2<<30 | 0x1c1<<21 | 0x08<<10,
- ALDEORH: 1<<30 | 0x1c1<<21 | 0x08<<10,
- ALDEORB: 0<<30 | 0x1c1<<21 | 0x08<<10,
- ALDEORLD: 3<<30 | 0x1c3<<21 | 0x08<<10,
- ALDEORLW: 2<<30 | 0x1c3<<21 | 0x08<<10,
- ALDEORLH: 1<<30 | 0x1c3<<21 | 0x08<<10,
- ALDEORLB: 0<<30 | 0x1c3<<21 | 0x08<<10,
- ALDORAD: 3<<30 | 0x1c5<<21 | 0x0c<<10,
- ALDORAW: 2<<30 | 0x1c5<<21 | 0x0c<<10,
- ALDORAH: 1<<30 | 0x1c5<<21 | 0x0c<<10,
- ALDORAB: 0<<30 | 0x1c5<<21 | 0x0c<<10,
- ALDORALD: 3<<30 | 0x1c7<<21 | 0x0c<<10,
- ALDORALW: 2<<30 | 0x1c7<<21 | 0x0c<<10,
- ALDORALH: 1<<30 | 0x1c7<<21 | 0x0c<<10,
- ALDORALB: 0<<30 | 0x1c7<<21 | 0x0c<<10,
- ALDORD: 3<<30 | 0x1c1<<21 | 0x0c<<10,
- ALDORW: 2<<30 | 0x1c1<<21 | 0x0c<<10,
- ALDORH: 1<<30 | 0x1c1<<21 | 0x0c<<10,
- ALDORB: 0<<30 | 0x1c1<<21 | 0x0c<<10,
- ALDORLD: 3<<30 | 0x1c3<<21 | 0x0c<<10,
- ALDORLW: 2<<30 | 0x1c3<<21 | 0x0c<<10,
- ALDORLH: 1<<30 | 0x1c3<<21 | 0x0c<<10,
- ALDORLB: 0<<30 | 0x1c3<<21 | 0x0c<<10,
- ASWPAD: 3<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAW: 2<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAH: 1<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPAB: 0<<30 | 0x1c5<<21 | 0x20<<10,
- ASWPALD: 3<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALW: 2<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALH: 1<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPALB: 0<<30 | 0x1c7<<21 | 0x20<<10,
- ASWPD: 3<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPW: 2<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPH: 1<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPB: 0<<30 | 0x1c1<<21 | 0x20<<10,
- ASWPLD: 3<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLW: 2<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLH: 1<<30 | 0x1c3<<21 | 0x20<<10,
- ASWPLB: 0<<30 | 0x1c3<<21 | 0x20<<10,
-}
-
-var oprange [ALAST & obj.AMask][]Optab
-
-var xcmp [C_NCLASS][C_NCLASS]bool
-
-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 FPOP3S(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 {
- return m<<31 | s<<29 | 0x1F<<24 | type_<<22 | op<<21 | op2<<15
-}
-
-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
-}
-
-func MOVCONST(d int64, s int, rt int) uint32 {
- return uint32(((d>>uint(s*16))&0xFFFF)<<5) | uint32(s)&3<<21 | uint32(rt&31)
-}
-
-const (
- // Optab.flag
- LFROM = 1 << 0 // p.From uses constant pool
- LTO = 1 << 1 // p.To uses constant pool
- NOTUSETMP = 1 << 2 // p expands to multiple instructions, but does NOT use REGTMP
-)
-
-var optab = []Optab{
- /* struct Optab:
- OPCODE, from, prog->reg, from3, to, type,size,param,flag,scond */
- {obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
-
- /* arithmetic operations */
- {AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AADC, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AADC, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {ANEG, C_REG, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0},
- {ANEG, C_NONE, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0},
- {ANGC, C_REG, C_NONE, C_NONE, C_REG, 17, 4, 0, 0, 0},
- {ACMP, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0},
- {AADD, C_ADDCON, C_RSP, C_NONE, C_RSP, 2, 4, 0, 0, 0},
- {AADD, C_ADDCON, C_NONE, C_NONE, C_RSP, 2, 4, 0, 0, 0},
- {ACMP, C_ADDCON, C_RSP, C_NONE, C_NONE, 2, 4, 0, 0, 0},
- {AADD, C_MOVCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0},
- {AADD, C_MOVCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0},
- {ACMP, C_MOVCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
- {AADD, C_BITCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0},
- {AADD, C_BITCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0},
- {ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
- {AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0},
- {AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0},
- {AADD, C_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0},
- {AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0},
- {AADD, C_MOVCON3, C_RSP, C_NONE, C_RSP, 13, 16, 0, 0, 0},
- {AADD, C_MOVCON3, C_NONE, C_NONE, C_RSP, 13, 16, 0, 0, 0},
- {AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 20, 0, 0, 0},
- {AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 20, 0, 0, 0},
- {ACMP, C_MOVCON2, C_REG, C_NONE, C_NONE, 13, 12, 0, 0, 0},
- {ACMP, C_MOVCON3, C_REG, C_NONE, C_NONE, 13, 16, 0, 0, 0},
- {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0},
- {AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {ACMP, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0},
- {ANEG, C_SHIFT, C_NONE, C_NONE, C_REG, 26, 4, 0, 0, 0},
- {AADD, C_REG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0},
- {AADD, C_REG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
- {ACMP, C_REG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0},
- {AADD, C_EXTREG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0},
- {AADD, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
- {AMVN, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
- {ACMP, C_EXTREG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0},
- {AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AMUL, C_REG, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
- {AMUL, C_REG, C_NONE, C_NONE, C_REG, 15, 4, 0, 0, 0},
- {AMADD, C_REG, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
- {AREM, C_REG, C_REG, C_NONE, C_REG, 16, 8, 0, 0, 0},
- {AREM, C_REG, C_NONE, C_NONE, C_REG, 16, 8, 0, 0, 0},
- {ASDIV, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {ASDIV, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
-
- {AFADDS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AFADDS, C_FREG, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AFMSUBD, C_FREG, C_FREG, C_FREG, C_FREG, 15, 4, 0, 0, 0},
- {AFCMPS, C_FREG, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0},
- {AFCMPS, C_FCON, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0},
- {AVADDP, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
- {AVADD, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
- {AVADD, C_VREG, C_VREG, C_NONE, C_VREG, 89, 4, 0, 0, 0},
- {AVADD, C_VREG, C_NONE, C_NONE, C_VREG, 89, 4, 0, 0, 0},
- {AVADDV, C_ARNG, C_NONE, C_NONE, C_VREG, 85, 4, 0, 0, 0},
-
- /* logical operations */
- {AAND, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AAND, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AANDS, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {AANDS, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
- {ATST, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0},
- {AAND, C_MBCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
- {AAND, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {AANDS, C_MBCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {AANDS, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {ATST, C_MBCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
- {AAND, C_BITCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
- {AAND, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
- {ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
- {AAND, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
- {AAND, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
- {AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
- {AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
- {ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0},
- {AAND, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
- {AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
- {AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
- {AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
- {AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
- {AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
- {AANDS, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
- {AANDS, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
- {AANDS, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
- {AANDS, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
- {AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
- {AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
- {ATST, C_MOVCON2, C_REG, C_NONE, C_NONE, 28, 12, 0, 0, 0},
- {ATST, C_MOVCON3, C_REG, C_NONE, C_NONE, 28, 16, 0, 0, 0},
- {ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 20, 0, 0, 0},
- {AAND, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AAND, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AANDS, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {AANDS, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
- {ATST, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0},
- {AMOVD, C_RSP, C_NONE, C_NONE, C_RSP, 24, 4, 0, 0, 0},
- {AMVN, C_REG, C_NONE, C_NONE, C_REG, 24, 4, 0, 0, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVHU */
- {AMOVW, C_REG, C_NONE, 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_NONE, C_REG, 32, 4, 0, 0, 0},
- {AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
- {AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
- {AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
- {AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0},
- {AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0},
- {AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, NOTUSETMP, 0},
- {AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, NOTUSETMP, 0},
-
- {AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
- {AMOVD, C_AACON, C_NONE, C_NONE, C_RSP, 4, 4, REGFROM, 0, 0},
- {AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, 0, 0},
-
- /* load long effective stack address (load int32 offset and add) */
- {AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0},
-
- // Move a large constant to a Vn.
- {AFMOVQ, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
- {AFMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
- {AFMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
-
- /* jump operations */
- {AB, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
- {ABL, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
- {AB, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
- {ABL, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
- {ABL, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
- {ABL, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
- {obj.ARET, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
- {obj.ARET, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
- {ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0},
- {ACBZ, C_REG, C_NONE, C_NONE, C_SBRA, 39, 4, 0, 0, 0},
- {ATBZ, C_VCON, C_REG, C_NONE, C_SBRA, 40, 4, 0, 0, 0},
- {AERET, C_NONE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
-
- // get a PC-relative address
- {AADRP, C_SBRA, C_NONE, C_NONE, C_REG, 60, 4, 0, 0, 0},
- {AADR, C_SBRA, C_NONE, C_NONE, C_REG, 61, 4, 0, 0, 0},
-
- {ACLREX, C_NONE, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0},
- {ACLREX, C_NONE, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0},
- {ABFM, C_VCON, C_REG, C_VCON, C_REG, 42, 4, 0, 0, 0},
- {ABFI, C_VCON, C_REG, C_VCON, C_REG, 43, 4, 0, 0, 0},
- {AEXTR, C_VCON, C_REG, C_REG, C_REG, 44, 4, 0, 0, 0},
- {ASXTB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
- {ACLS, C_REG, C_NONE, C_NONE, C_REG, 46, 4, 0, 0, 0},
- {ALSL, C_VCON, C_REG, C_NONE, C_REG, 8, 4, 0, 0, 0},
- {ALSL, C_VCON, C_NONE, C_NONE, C_REG, 8, 4, 0, 0, 0},
- {ALSL, C_REG, C_NONE, C_NONE, C_REG, 9, 4, 0, 0, 0},
- {ALSL, C_REG, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
- {ASVC, C_VCON, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
- {ASVC, C_NONE, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
- {ADWORD, C_NONE, C_NONE, C_NONE, C_VCON, 11, 8, 0, NOTUSETMP, 0},
- {ADWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 11, 8, 0, NOTUSETMP, 0},
- {ADWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 11, 8, 0, NOTUSETMP, 0},
- {ADWORD, C_NONE, C_NONE, C_NONE, C_LACON, 11, 8, 0, NOTUSETMP, 0},
- {AWORD, C_NONE, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0},
- {AWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0},
- {AMOVW, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0},
- {AMOVD, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
- {AMOVBU, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
- {AMOVH, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
- {AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
- {AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
- {AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 71, 8, 0, 0, 0},
- {AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 69, 4, 0, 0, 0},
- {AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 70, 8, 0, 0, 0},
-
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AFMOVS, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
- {AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0},
- {AFMOVS, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AFMOVD, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
- {AFMOVS, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
- {AFMOVD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
- {AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
- {ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
- {AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
- {AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0},
- {AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0},
- {AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0},
- {AVMOV, C_REG, C_NONE, C_NONE, C_ARNG, 82, 4, 0, 0, 0},
- {AVMOV, C_REG, C_NONE, C_NONE, C_ELEM, 78, 4, 0, 0, 0},
- {AVMOV, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
- {AVDUP, C_ELEM, C_NONE, C_NONE, C_ARNG, 79, 4, 0, 0, 0},
- {AVMOVI, C_ADDCON, C_NONE, C_NONE, C_ARNG, 86, 4, 0, 0, 0},
- {AVFMLA, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
- {AVEXT, C_VCON, C_ARNG, C_ARNG, C_ARNG, 94, 4, 0, 0, 0},
- {AVTBL, C_ARNG, C_NONE, C_LIST, C_ARNG, 100, 4, 0, 0, 0},
- {AVUSHR, C_VCON, C_ARNG, C_NONE, C_ARNG, 95, 4, 0, 0, 0},
- {AVZIP1, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
- {AVUSHLL, C_VCON, C_ARNG, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
- {AVUXTL, C_ARNG, C_NONE, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
-
- /* conditional operations */
- {ACSEL, C_COND, C_REG, C_REG, C_REG, 18, 4, 0, 0, 0},
- {ACINC, C_COND, C_REG, C_NONE, C_REG, 18, 4, 0, 0, 0},
- {ACSET, C_COND, C_NONE, C_NONE, C_REG, 18, 4, 0, 0, 0},
- {AFCSELD, C_COND, C_FREG, C_FREG, C_FREG, 18, 4, 0, 0, 0},
- {ACCMN, C_COND, C_REG, C_REG, C_VCON, 19, 4, 0, 0, 0},
- {ACCMN, C_COND, C_REG, C_VCON, C_VCON, 19, 4, 0, 0, 0},
- {AFCCMPS, C_COND, C_FREG, C_FREG, C_VCON, 57, 4, 0, 0, 0},
-
- /* scaled 12-bit unsigned displacement store */
- {AMOVB, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_UAUTO8K, 20, 4, REGSP, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_UOREG8K, 20, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
-
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
-
- /* unscaled 9-bit signed displacement store */
- {AMOVB, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
-
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
-
- /* scaled 12-bit unsigned displacement load */
- {AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVBU, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVH, C_UAUTO8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVW, C_UAUTO16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVD, C_UAUTO32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
-
- {AFMOVS, C_UAUTO16K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
- {AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
- {AFMOVD, C_UAUTO32K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
- {AFMOVD, C_UOREG32K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
-
- /* unscaled 9-bit signed displacement load */
- {AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVBU, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVH, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVW, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
- {AMOVD, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
- {AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
-
- {AFMOVS, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
- {AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
- {AFMOVD, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
- {AFMOVD, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
-
- /* long displacement store */
- {AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
-
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
-
- /* long displacement load */
- {AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVBU, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVH, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
- {AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
- {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
-
- {AFMOVS, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
- {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
- {AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
- {AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
-
- /* pre/post-indexed load (unscaled, signed 9-bit offset) */
- {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
- {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
- {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
- {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
- {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
- {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
- {AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
-
- {AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
- {AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
- {AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
- {AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
- {AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
- {AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
- {AFMOVD, C_LOREG, C_NONE, 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_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
-
- {AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
-
- /* load with shifted or extended register offset */
- {AMOVD, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
- {AMOVW, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
- {AMOVH, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
- {AMOVB, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
- {AMOVBU, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
- {AFMOVS, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0},
- {AFMOVD, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0},
-
- /* store with extended register offset */
- {AMOVD, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
- {AMOVW, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
- {AMOVH, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
- {AMOVB, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
- {AFMOVS, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
- {AFMOVD, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
-
- /* pre/post-indexed/signed-offset load/store register pair
- (unscaled, signed 10-bit quad-aligned and long offset) */
- {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
- {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
- {ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
- {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
- {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
- {ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
- {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
- {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
- {ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
- {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
- {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
- {ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
- {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
- {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
- {ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
- {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
- {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
- {ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
- {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
- {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
- {ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
- {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
- {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
- {ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
- {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
- {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
- {ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
- {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
- {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
- {ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
- {ALDP, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
-
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
- {ASTP, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
-
- // differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4
- {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
- {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
- {ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
- {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
- {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
- {ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
- {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
- {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
- {ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
- {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
- {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
- {ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
- {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
- {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
- {ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
- {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
- {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
- {ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
- {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
- {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
- {ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
- {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
- {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
- {ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
- {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
- {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
- {ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
- {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
- {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
- {ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
- {ALDPW, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
-
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
- {ASTPW, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
-
- {ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG
- {ASWPD, C_REG, C_NONE, C_NONE, C_ZAUTO, 47, 4, REGSP, 0, 0}, // RegTo2=C_REG
- {ALDAR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
- {ALDXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
- {ALDAXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
- {ALDXP, C_ZOREG, C_NONE, C_NONE, C_PAIR, 58, 4, 0, 0, 0},
- {ASTLR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_NONE
- {ASTXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG
- {ASTLXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG
- {ASTXP, C_PAIR, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0},
-
- /* VLD[1-4]/VST[1-4] */
- {AVLD1, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0},
- {AVLD1, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
- {AVLD1, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
- {AVLD1R, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0},
- {AVLD1R, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
- {AVLD1R, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
- {AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST},
- {AVLD1, C_ROFF, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST},
- {AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, 0},
- {AVST1, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
- {AVST1, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
- {AVST1, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
- {AVST2, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
- {AVST2, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
- {AVST2, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
- {AVST3, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
- {AVST3, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
- {AVST3, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
- {AVST4, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
- {AVST4, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
- {AVST4, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
- {AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, C_XPOST},
- {AVST1, C_ELEM, C_NONE, C_NONE, C_ROFF, 96, 4, 0, 0, C_XPOST},
- {AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, 0},
-
- /* special */
- {AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0},
- {AMRS, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0},
- {AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0},
- {AMSR, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0},
- {AMOVD, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
- {AMSR, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
- {APRFM, C_UOREG32K, C_NONE, C_NONE, C_SPR, 91, 4, 0, 0, 0},
- {APRFM, C_UOREG32K, C_NONE, C_NONE, C_LCON, 91, 4, 0, 0, 0},
- {ADMB, C_VCON, C_NONE, C_NONE, C_NONE, 51, 4, 0, 0, 0},
- {AHINT, C_VCON, C_NONE, C_NONE, C_NONE, 52, 4, 0, 0, 0},
- {ASYS, C_VCON, C_NONE, C_NONE, C_NONE, 50, 4, 0, 0, 0},
- {ASYS, C_VCON, C_REG, C_NONE, C_NONE, 50, 4, 0, 0, 0},
- {ASYSL, C_VCON, C_NONE, C_NONE, C_REG, 50, 4, 0, 0, 0},
-
- /* encryption instructions */
- {AAESD, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0}, // for compatibility with old code
- {AAESD, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0}, // recommend using the new one for better readability
- {ASHA1C, C_VREG, C_REG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
- {ASHA1C, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
- {ASHA1H, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0},
- {ASHA1SU0, C_ARNG, C_ARNG, C_NONE, C_ARNG, 1, 4, 0, 0, 0},
- {ASHA256H, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
- {AVREV32, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
- {AVPMULL, C_ARNG, C_ARNG, C_NONE, C_ARNG, 93, 4, 0, 0, 0},
-
- {obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
- {obj.APCDATA, C_VCON, C_NONE, C_NONE, C_VCON, 0, 0, 0, 0, 0},
- {obj.AFUNCDATA, C_VCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
- {obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
- {obj.ANOP, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // nop variants, see #40689
- {obj.ANOP, C_REG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
- {obj.ANOP, C_VREG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
- {obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
- {obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
- {obj.APCALIGN, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // align code
-
- {obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
-}
-
-/*
- * valid pstate field values, and value to use in instruction
- */
-var pstatefield = []struct {
- reg int16
- enc 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 prfopfield = []struct {
- reg int16
- enc uint32
-}{
- {REG_PLDL1KEEP, 0},
- {REG_PLDL1STRM, 1},
- {REG_PLDL2KEEP, 2},
- {REG_PLDL2STRM, 3},
- {REG_PLDL3KEEP, 4},
- {REG_PLDL3STRM, 5},
- {REG_PLIL1KEEP, 8},
- {REG_PLIL1STRM, 9},
- {REG_PLIL2KEEP, 10},
- {REG_PLIL2STRM, 11},
- {REG_PLIL3KEEP, 12},
- {REG_PLIL3STRM, 13},
- {REG_PSTL1KEEP, 16},
- {REG_PSTL1STRM, 17},
- {REG_PSTL2KEEP, 18},
- {REG_PSTL2STRM, 19},
- {REG_PSTL3KEEP, 20},
- {REG_PSTL3STRM, 21},
-}
-
-// Used for padinng NOOP instruction
-const OP_NOOP = 0xd503201f
-
-// align code to a certain length by padding bytes.
-func pcAlignPadLength(pc int64, alignedValue int64, ctxt *obj.Link) int {
- if !((alignedValue&(alignedValue-1) == 0) && 8 <= alignedValue && alignedValue <= 2048) {
- ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", alignedValue)
- }
- return int(-pc & (alignedValue - 1))
-}
-
-func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
- if ctxt.Retpoline {
- ctxt.Diag("-spectre=ret not supported on arm64")
- ctxt.Retpoline = false // don't keep printing
- }
-
- p := cursym.Func.Text
- if p == nil || p.Link == nil { // handle external functions and ELF section symbols
- return
- }
-
- if oprange[AAND&obj.AMask] == nil {
- ctxt.Diag("arm64 ops not initialized, call arm64.buildop first")
- }
-
- c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset & 0xffffffff), extrasize: int32(p.To.Offset >> 32)}
- p.To.Offset &= 0xffffffff // extrasize is no longer needed
-
- bflag := 1
- pc := int64(0)
- p.Pc = pc
- var m int
- var o *Optab
- for p = p.Link; p != nil; p = p.Link {
- if p.As == ADWORD && (pc&7) != 0 {
- pc += 4
- }
- p.Pc = pc
- o = c.oplook(p)
- m = int(o.size)
- if m == 0 {
- switch p.As {
- case obj.APCALIGN:
- alignedValue := p.From.Offset
- m = pcAlignPadLength(pc, alignedValue, ctxt)
- // Update the current text symbol alignment value.
- if int32(alignedValue) > cursym.Func.Align {
- cursym.Func.Align = int32(alignedValue)
- }
- break
- case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
- continue
- default:
- c.ctxt.Diag("zero-width instruction\n%v", p)
- }
- }
- switch o.flag & (LFROM | LTO) {
- case LFROM:
- c.addpool(p, &p.From)
-
- case LTO:
- c.addpool(p, &p.To)
- break
- }
-
- if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
- c.checkpool(p, 0)
- }
- pc += int64(m)
- if c.blitrl != nil {
- c.checkpool(p, 1)
- }
- }
-
- c.cursym.Size = pc
-
- /*
- * 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
- pc = 0
- for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
- if p.As == ADWORD && (pc&7) != 0 {
- pc += 4
- }
- p.Pc = pc
- o = c.oplook(p)
-
- /* very large branches */
- if (o.type_ == 7 || o.type_ == 39 || o.type_ == 40) && p.To.Target() != nil { // 7: BEQ and like, 39: CBZ and like, 40: TBZ and like
- otxt := p.To.Target().Pc - pc
- var toofar bool
- switch o.type_ {
- case 7, 39: // branch instruction encodes 19 bits
- toofar = otxt <= -(1<<20)+10 || otxt >= (1<<20)-10
- case 40: // branch instruction encodes 14 bits
- toofar = otxt <= -(1<<15)+10 || otxt >= (1<<15)-10
- }
- if toofar {
- q := c.newprog()
- q.Link = p.Link
- p.Link = q
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(p.To.Target())
- p.To.SetTarget(q)
- q = c.newprog()
- q.Link = p.Link
- p.Link = q
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(q.Link.Link)
- bflag = 1
- }
- }
- m = int(o.size)
-
- if m == 0 {
- switch p.As {
- case obj.APCALIGN:
- alignedValue := p.From.Offset
- m = pcAlignPadLength(pc, alignedValue, ctxt)
- break
- case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
- continue
- default:
- c.ctxt.Diag("zero-width instruction\n%v", p)
- }
- }
-
- pc += int64(m)
- }
- }
-
- pc += -pc & (funcAlign - 1)
- c.cursym.Size = pc
-
- /*
- * lay out the code, emitting code and data relocations.
- */
- c.cursym.Grow(c.cursym.Size)
- bp := c.cursym.P
- psz := int32(0)
- var i int
- var out [6]uint32
- for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
- c.pc = p.Pc
- o = c.oplook(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)
- }
- if p.As == obj.APCALIGN {
- alignedValue := p.From.Offset
- v := pcAlignPadLength(p.Pc, alignedValue, c.ctxt)
- for i = 0; i < int(v/4); i++ {
- // emit ANOOP instruction by the padding size
- c.ctxt.Arch.ByteOrder.PutUint32(bp, OP_NOOP)
- bp = bp[4:]
- psz += 4
- }
- } else {
- c.asmout(p, o, out[:])
- for i = 0; i < int(o.size/4); i++ {
- c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
- bp = bp[4:]
- psz += 4
- }
- }
- }
-
- // Mark nonpreemptible instruction sequences.
- // We use REGTMP as a scratch register during call injection,
- // so instruction sequences that use REGTMP are unsafe to
- // preempt asynchronously.
- obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
-}
-
-// isUnsafePoint returns whether p is an unsafe point.
-func (c *ctxt7) isUnsafePoint(p *obj.Prog) bool {
- // If p explicitly uses REGTMP, it's unsafe to preempt, because the
- // preemption sequence clobbers REGTMP.
- return p.From.Reg == REGTMP || p.To.Reg == REGTMP || p.Reg == REGTMP
-}
-
-// isRestartable returns whether p is a multi-instruction sequence that,
-// if preempted, can be restarted.
-func (c *ctxt7) isRestartable(p *obj.Prog) bool {
- if c.isUnsafePoint(p) {
- return false
- }
- // If p is a multi-instruction sequence with uses REGTMP inserted by
- // the assembler in order to materialize a large constant/offset, we
- // can restart p (at the start of the instruction sequence), recompute
- // the content of REGTMP, upon async preemption. Currently, all cases
- // of assembler-inserted REGTMP fall into this category.
- // If p doesn't use REGTMP, it can be simply preempted, so we don't
- // mark it.
- o := c.oplook(p)
- return o.size > 4 && o.flag&NOTUSETMP == 0
-}
-
-/*
- * 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 (c *ctxt7) checkpool(p *obj.Prog, skip int) {
- if c.pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(c.pool.size)-int64(c.pool.start)+8)) {
- c.flushpool(p, skip)
- } else if p.Link == nil {
- c.flushpool(p, 2)
- }
-}
-
-func (c *ctxt7) flushpool(p *obj.Prog, skip int) {
- if c.blitrl != nil {
- if skip != 0 {
- if c.ctxt.Debugvlog && skip == 1 {
- fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
- }
- q := c.newprog()
- q.As = AB
- q.To.Type = obj.TYPE_BRANCH
- q.To.SetTarget(p.Link)
- q.Link = c.blitrl
- q.Pos = p.Pos
- c.blitrl = q
- } else if p.Pc+int64(c.pool.size)-int64(c.pool.start) < maxPCDisp {
- return
- }
-
- // The line number for constant pool entries doesn't really matter.
- // We set it to the line number of the preceding instruction so that
- // there are no deltas to encode in the pc-line tables.
- for q := c.blitrl; q != nil; q = q.Link {
- q.Pos = p.Pos
- }
-
- c.elitrl.Link = p.Link
- p.Link = c.blitrl
-
- c.blitrl = nil /* BUG: should refer back to values until out-of-range */
- c.elitrl = nil
- c.pool.size = 0
- c.pool.start = 0
- }
-}
-
-/*
- * MOVD foo(SB), R is actually
- * MOVD addr, REGTMP
- * MOVD REGTMP, R
- * where addr is the address of the DWORD containing the address of foo.
- *
- * TODO: hash
- */
-func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
- cls := c.aclass(a)
- lit := c.instoffset
- t := c.newprog()
- t.As = AWORD
- sz := 4
-
- if a.Type == obj.TYPE_CONST {
- if lit != int64(int32(lit)) && uint64(lit) != uint64(uint32(lit)) {
- // out of range -0x80000000 ~ 0xffffffff, must store 64-bit
- t.As = ADWORD
- sz = 8
- } // else store 32-bit
- } else if p.As == AMOVD && a.Type != obj.TYPE_MEM || cls == C_ADDR || cls == C_VCON || lit != int64(int32(lit)) || uint64(lit) != uint64(uint32(lit)) {
- // conservative: don't know if we want signed or unsigned extension.
- // in case of ambiguity, store 64-bit
- t.As = ADWORD
- sz = 8
- }
-
- switch cls {
- // TODO(aram): remove.
- default:
- if a.Name != obj.NAME_EXTERN {
- fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(cls), p)
- }
-
- t.To.Offset = a.Offset
- t.To.Sym = a.Sym
- t.To.Type = a.Type
- t.To.Name = a.Name
-
- /* This is here because MOV uint12<<12, R is disabled in optab.
- Because of this, we need to load the constant from memory. */
- case C_ADDCON:
- fallthrough
-
- case C_ZAUTO,
- C_PSAUTO,
- C_PSAUTO_8,
- C_PSAUTO_4,
- C_PPAUTO,
- C_UAUTO4K_8,
- C_UAUTO4K_4,
- C_UAUTO4K_2,
- C_UAUTO4K,
- C_UAUTO8K_8,
- C_UAUTO8K_4,
- C_UAUTO8K,
- C_UAUTO16K_8,
- C_UAUTO16K,
- C_UAUTO32K,
- C_NSAUTO_8,
- C_NSAUTO_4,
- C_NSAUTO,
- C_NPAUTO,
- C_NAUTO4K,
- C_LAUTO,
- C_PPOREG,
- C_PSOREG,
- C_PSOREG_4,
- C_PSOREG_8,
- C_UOREG4K_8,
- C_UOREG4K_4,
- C_UOREG4K_2,
- C_UOREG4K,
- C_UOREG8K_8,
- C_UOREG8K_4,
- C_UOREG8K,
- C_UOREG16K_8,
- C_UOREG16K,
- C_UOREG32K,
- C_NSOREG_8,
- C_NSOREG_4,
- C_NSOREG,
- C_NPOREG,
- C_NOREG4K,
- C_LOREG,
- C_LACON,
- C_ADDCON2,
- C_LCON,
- C_VCON:
- if a.Name == obj.NAME_EXTERN {
- fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p)
- }
-
- t.To.Type = obj.TYPE_CONST
- t.To.Offset = lit
- break
- }
-
- for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
- if q.To == t.To {
- p.Pool = q
- return
- }
- }
-
- q := c.newprog()
- *q = *t
- q.Pc = int64(c.pool.size)
- if c.blitrl == nil {
- c.blitrl = q
- c.pool.start = uint32(p.Pc)
- } else {
- c.elitrl.Link = q
- }
- c.elitrl = q
- c.pool.size = -c.pool.size & (funcAlign - 1)
- c.pool.size += uint32(sz)
- p.Pool = q
-}
-
-func (c *ctxt7) regoff(a *obj.Addr) uint32 {
- c.instoffset = 0
- c.aclass(a)
- return uint32(c.instoffset)
-}
-
-func isSTLXRop(op obj.As) bool {
- switch op {
- case ASTLXR, ASTLXRW, ASTLXRB, ASTLXRH,
- ASTXR, ASTXRW, ASTXRB, ASTXRH:
- return true
- }
- return false
-}
-
-func isSTXPop(op obj.As) bool {
- switch op {
- case ASTXP, ASTLXP, ASTXPW, ASTLXPW:
- return true
- }
- return false
-}
-
-func isANDop(op obj.As) bool {
- switch op {
- case AAND, AORR, AEOR, AANDS, ATST,
- ABIC, AEON, AORN, ABICS:
- return true
- }
- return false
-}
-
-func isANDWop(op obj.As) bool {
- switch op {
- case AANDW, AORRW, AEORW, AANDSW, ATSTW,
- ABICW, AEONW, AORNW, ABICSW:
- return true
- }
- return false
-}
-
-func isADDop(op obj.As) bool {
- switch op {
- case AADD, AADDS, ASUB, ASUBS, ACMN, ACMP:
- return true
- }
- return false
-}
-
-func isADDWop(op obj.As) bool {
- switch op {
- case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
- return true
- }
- return false
-}
-
-func isRegShiftOrExt(a *obj.Addr) bool {
- return (a.Index-obj.RBaseARM64)&REG_EXT != 0 || (a.Index-obj.RBaseARM64)&REG_LSL != 0
-}
-
-// Maximum PC-relative displacement.
-// The actual limit is ±2²⁰, but we are conservative
-// to avoid needing to recompute the literal pool flush points
-// as span-dependent jumps are enlarged.
-const maxPCDisp = 512 * 1024
-
-// ispcdisp reports whether v is a valid PC-relative displacement.
-func ispcdisp(v int32) bool {
- return -maxPCDisp < v && v < maxPCDisp && v&3 == 0
-}
-
-func isaddcon(v int64) bool {
- /* uimm12 or uimm24? */
- if v < 0 {
- return false
- }
- if (v & 0xFFF) == 0 {
- v >>= 12
- }
- return v <= 0xFFF
-}
-
-func isaddcon2(v int64) bool {
- return 0 <= v && v <= 0xFFFFFF
-}
-
-// isbitcon reports whether a constant can be encoded into a logical instruction.
-// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64,
-// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones.
-// special cases: 0 and -1 are not bitcon.
-// this function needs to run against virtually all the constants, so it needs to be fast.
-// for this reason, bitcon testing and bitcon encoding are separate functions.
-func isbitcon(x uint64) bool {
- if x == 1<<64-1 || x == 0 {
- return false
- }
- // determine the period and sign-extend a unit to 64 bits
- switch {
- case x != x>>32|x<<32:
- // period is 64
- // nothing to do
- case x != x>>16|x<<48:
- // period is 32
- x = uint64(int64(int32(x)))
- case x != x>>8|x<<56:
- // period is 16
- x = uint64(int64(int16(x)))
- case x != x>>4|x<<60:
- // period is 8
- x = uint64(int64(int8(x)))
- default:
- // period is 4 or 2, always true
- // 0001, 0010, 0100, 1000 -- 0001 rotate
- // 0011, 0110, 1100, 1001 -- 0011 rotate
- // 0111, 1011, 1101, 1110 -- 0111 rotate
- // 0101, 1010 -- 01 rotate, repeat
- return true
- }
- return sequenceOfOnes(x) || sequenceOfOnes(^x)
-}
-
-// sequenceOfOnes tests whether a constant is a sequence of ones in binary, with leading and trailing zeros
-func sequenceOfOnes(x uint64) bool {
- y := x & -x // lowest set bit of x. x is good iff x+y is a power of 2
- y += x
- return (y-1)&y == 0
-}
-
-// bitconEncode returns the encoding of a bitcon used in logical instructions
-// x is known to be a bitcon
-// a bitcon is a sequence of n ones at low bits (i.e. 1<<n-1), right rotated
-// by R bits, and repeated with period of 64, 32, 16, 8, 4, or 2.
-// it is encoded in logical instructions with 3 bitfields
-// N (1 bit) : R (6 bits) : S (6 bits), where
-// N=1 -- period=64
-// N=0, S=0xxxxx -- period=32
-// N=0, S=10xxxx -- period=16
-// N=0, S=110xxx -- period=8
-// N=0, S=1110xx -- period=4
-// N=0, S=11110x -- period=2
-// R is the shift amount, low bits of S = n-1
-func bitconEncode(x uint64, mode int) uint32 {
- var period uint32
- // determine the period and sign-extend a unit to 64 bits
- switch {
- case x != x>>32|x<<32:
- period = 64
- case x != x>>16|x<<48:
- period = 32
- x = uint64(int64(int32(x)))
- case x != x>>8|x<<56:
- period = 16
- x = uint64(int64(int16(x)))
- case x != x>>4|x<<60:
- period = 8
- x = uint64(int64(int8(x)))
- case x != x>>2|x<<62:
- period = 4
- x = uint64(int64(x<<60) >> 60)
- default:
- period = 2
- x = uint64(int64(x<<62) >> 62)
- }
- neg := false
- if int64(x) < 0 {
- x = ^x
- neg = true
- }
- y := x & -x // lowest set bit of x.
- s := log2(y)
- n := log2(x+y) - s // x (or ^x) is a sequence of n ones left shifted by s bits
- if neg {
- // ^x is a sequence of n ones left shifted by s bits
- // adjust n, s for x
- s = n + s
- n = period - n
- }
-
- N := uint32(0)
- if mode == 64 && period == 64 {
- N = 1
- }
- R := (period - s) & (period - 1) & uint32(mode-1) // shift amount of right rotate
- S := (n - 1) | 63&^(period<<1-1) // low bits = #ones - 1, high bits encodes period
- return N<<22 | R<<16 | S<<10
-}
-
-func log2(x uint64) uint32 {
- if x == 0 {
- panic("log2 of 0")
- }
- n := uint32(0)
- if x >= 1<<32 {
- x >>= 32
- n += 32
- }
- if x >= 1<<16 {
- x >>= 16
- n += 16
- }
- if x >= 1<<8 {
- x >>= 8
- n += 8
- }
- if x >= 1<<4 {
- x >>= 4
- n += 4
- }
- if x >= 1<<2 {
- x >>= 2
- n += 2
- }
- if x >= 1<<1 {
- x >>= 1
- n += 1
- }
- return n
-}
-
-func autoclass(l int64) int {
- if l == 0 {
- return C_ZAUTO
- }
-
- if l < 0 {
- if l >= -256 && (l&7) == 0 {
- return C_NSAUTO_8
- }
- if l >= -256 && (l&3) == 0 {
- return C_NSAUTO_4
- }
- if l >= -256 {
- return C_NSAUTO
- }
- if l >= -512 && (l&7) == 0 {
- return C_NPAUTO
- }
- if l >= -4095 {
- return C_NAUTO4K
- }
- return C_LAUTO
- }
-
- if l <= 255 {
- if (l & 7) == 0 {
- return C_PSAUTO_8
- }
- if (l & 3) == 0 {
- return C_PSAUTO_4
- }
- return C_PSAUTO
- }
- if l <= 504 && l&7 == 0 {
- return C_PPAUTO
- }
- if l <= 4095 {
- if l&7 == 0 {
- return C_UAUTO4K_8
- }
- if l&3 == 0 {
- return C_UAUTO4K_4
- }
- if l&1 == 0 {
- return C_UAUTO4K_2
- }
- return C_UAUTO4K
- }
- if l <= 8190 {
- if l&7 == 0 {
- return C_UAUTO8K_8
- }
- if l&3 == 0 {
- return C_UAUTO8K_4
- }
- if l&1 == 0 {
- return C_UAUTO8K
- }
- }
- if l <= 16380 {
- if l&7 == 0 {
- return C_UAUTO16K_8
- }
- if l&3 == 0 {
- return C_UAUTO16K
- }
- }
- if l <= 32760 && (l&7) == 0 {
- return C_UAUTO32K
- }
- return C_LAUTO
-}
-
-func oregclass(l int64) int {
- return autoclass(l) - C_ZAUTO + C_ZOREG
-}
-
-/*
- * given an offset v and a class c (see above)
- * return the offset value to use in the instruction,
- * scaled if necessary
- */
-func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 {
- s := 0
- if cls >= C_SEXT1 && cls <= C_SEXT16 {
- s = cls - C_SEXT1
- } else {
- switch cls {
- case C_UAUTO4K, C_UOREG4K, C_ZOREG:
- s = 0
- case C_UAUTO8K, C_UOREG8K:
- s = 1
- case C_UAUTO16K, C_UOREG16K:
- s = 2
- case C_UAUTO32K, C_UOREG32K:
- s = 3
- default:
- c.ctxt.Diag("bad class: %v\n%v", DRconv(cls), p)
- }
- }
- vs := v >> uint(s)
- if vs<<uint(s) != v {
- c.ctxt.Diag("odd offset: %d\n%v", v, p)
- }
- return vs
-}
-
-/*
- * if v contains a single 16-bit value aligned
- * on a 16-bit field, and thus suitable for movk/movn,
- * return the field index 0 to 3; otherwise return -1
- */
-func movcon(v int64) int {
- for s := 0; s < 64; s += 16 {
- if (uint64(v) &^ (uint64(0xFFFF) << uint(s))) == 0 {
- return s / 16
- }
- }
- return -1
-}
-
-func rclass(r int16) int {
- switch {
- case REG_R0 <= r && r <= REG_R30: // not 31
- return C_REG
- case r == REGZERO:
- return C_ZCON
- case REG_F0 <= r && r <= REG_F31:
- return C_FREG
- case REG_V0 <= r && r <= REG_V31:
- return C_VREG
- case COND_EQ <= r && r <= COND_NV:
- return C_COND
- case r == REGSP:
- return C_RSP
- case r >= REG_ARNG && r < REG_ELEM:
- return C_ARNG
- case r >= REG_ELEM && r < REG_ELEM_END:
- return C_ELEM
- case r >= REG_UXTB && r < REG_SPECIAL:
- return C_EXTREG
- case r >= REG_SPECIAL:
- return C_SPR
- }
- return C_GOK
-}
-
-// con32class reclassifies the constant of 32-bit instruction. Because the constant type is 32-bit,
-// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
-func (c *ctxt7) con32class(a *obj.Addr) int {
- v := uint32(a.Offset)
- if v == 0 {
- return C_ZCON
- }
- if isaddcon(int64(v)) {
- if v <= 0xFFF {
- if isbitcon(uint64(a.Offset)) {
- return C_ABCON0
- }
- return C_ADDCON0
- }
- if isbitcon(uint64(a.Offset)) {
- return C_ABCON
- }
- if movcon(int64(v)) >= 0 {
- return C_AMCON
- }
- if movcon(int64(^v)) >= 0 {
- return C_AMCON
- }
- return C_ADDCON
- }
-
- t := movcon(int64(v))
- if t >= 0 {
- if isbitcon(uint64(a.Offset)) {
- return C_MBCON
- }
- return C_MOVCON
- }
-
- t = movcon(int64(^v))
- if t >= 0 {
- if isbitcon(uint64(a.Offset)) {
- return C_MBCON
- }
- return C_MOVCON
- }
-
- if isbitcon(uint64(a.Offset)) {
- return C_BITCON
- }
-
- if 0 <= v && v <= 0xffffff {
- return C_ADDCON2
- }
- return C_LCON
-}
-
-// con64class reclassifies the constant of C_VCON and C_LCON class.
-func (c *ctxt7) con64class(a *obj.Addr) int {
- zeroCount := 0
- negCount := 0
- for i := uint(0); i < 4; i++ {
- immh := uint32(a.Offset >> (i * 16) & 0xffff)
- if immh == 0 {
- zeroCount++
- } else if immh == 0xffff {
- negCount++
- }
- }
- if zeroCount >= 3 || negCount >= 3 {
- return C_MOVCON
- } else if zeroCount == 2 || negCount == 2 {
- return C_MOVCON2
- } else if zeroCount == 1 || negCount == 1 {
- return C_MOVCON3
- } else {
- return C_VCON
- }
-}
-
-func (c *ctxt7) aclass(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_REGLIST:
- return C_LIST
-
- case obj.TYPE_MEM:
- // The base register should be an integer register.
- if int16(REG_F0) <= a.Reg && a.Reg <= int16(REG_V31) {
- break
- }
- switch a.Name {
- case obj.NAME_EXTERN, obj.NAME_STATIC:
- if a.Sym == nil {
- break
- }
- c.instoffset = a.Offset
- if a.Sym != nil { // use relocation
- if a.Sym.Type == objabi.STLSBSS {
- if c.ctxt.Flag_shared {
- return C_TLS_IE
- } else {
- return C_TLS_LE
- }
- }
- return C_ADDR
- }
- return C_LEXT
-
- case obj.NAME_GOTREF:
- return C_GOTADDR
-
- case obj.NAME_AUTO:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-SP.
- a.Reg = obj.REG_NONE
- }
- // The frame top 8 or 16 bytes are for FP
- c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize)
- return autoclass(c.instoffset)
-
- case obj.NAME_PARAM:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-FP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = int64(c.autosize) + a.Offset + 8
- return autoclass(c.instoffset)
-
- case obj.NAME_NONE:
- if a.Index != 0 {
- if a.Offset != 0 {
- if isRegShiftOrExt(a) {
- // extended or shifted register offset, (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2).
- return C_ROFF
- }
- return C_GOK
- }
- // register offset, (Rn)(Rm)
- return C_ROFF
- }
- c.instoffset = a.Offset
- return oregclass(c.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.NAME_NONE:
- c.instoffset = a.Offset
- if a.Reg != 0 && a.Reg != REGZERO {
- break
- }
- v := c.instoffset
- if v == 0 {
- return C_ZCON
- }
- if isaddcon(v) {
- if v <= 0xFFF {
- if isbitcon(uint64(v)) {
- return C_ABCON0
- }
- return C_ADDCON0
- }
- if isbitcon(uint64(v)) {
- return C_ABCON
- }
- if movcon(v) >= 0 {
- return C_AMCON
- }
- if movcon(^v) >= 0 {
- return C_AMCON
- }
- return C_ADDCON
- }
-
- t := movcon(v)
- if t >= 0 {
- if isbitcon(uint64(v)) {
- return C_MBCON
- }
- return C_MOVCON
- }
-
- t = movcon(^v)
- if t >= 0 {
- if isbitcon(uint64(v)) {
- return C_MBCON
- }
- return C_MOVCON
- }
-
- if isbitcon(uint64(v)) {
- return C_BITCON
- }
-
- if 0 <= v && v <= 0xffffff {
- return C_ADDCON2
- }
-
- if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) {
- return C_LCON
- }
- return C_VCON
-
- case obj.NAME_EXTERN, obj.NAME_STATIC:
- if a.Sym == nil {
- return C_GOK
- }
- if a.Sym.Type == objabi.STLSBSS {
- c.ctxt.Diag("taking address of TLS variable is not supported")
- }
- c.instoffset = a.Offset
- return C_VCONADDR
-
- case obj.NAME_AUTO:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-SP.
- a.Reg = obj.REG_NONE
- }
- // The frame top 8 or 16 bytes are for FP
- c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize)
-
- case obj.NAME_PARAM:
- if a.Reg == REGSP {
- // unset base register for better printing, since
- // a.Offset is still relative to pseudo-FP.
- a.Reg = obj.REG_NONE
- }
- c.instoffset = int64(c.autosize) + a.Offset + 8
- default:
- return C_GOK
- }
- cf := c.instoffset
- if isaddcon(cf) || isaddcon(-cf) {
- return C_AACON
- }
- if isaddcon2(cf) {
- return C_AACON2
- }
-
- return C_LACON
-
- case obj.TYPE_BRANCH:
- return C_SBRA
- }
-
- return C_GOK
-}
-
-func oclass(a *obj.Addr) int {
- return int(a.Class) - 1
-}
-
-func (c *ctxt7) oplook(p *obj.Prog) *Optab {
- a1 := int(p.Optab)
- if a1 != 0 {
- return &optab[a1-1]
- }
- a1 = int(p.From.Class)
- if a1 == 0 {
- a0 := c.aclass(&p.From)
- // do not break C_ADDCON2 when S bit is set
- if (p.As == AADDS || p.As == AADDSW || p.As == ASUBS || p.As == ASUBSW) && a0 == C_ADDCON2 {
- a0 = C_LCON
- }
- a1 = a0 + 1
- p.From.Class = int8(a1)
- // more specific classification of 32-bit integers
- if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE {
- if p.As == AMOVW || isADDWop(p.As) {
- ra0 := c.con32class(&p.From)
- // do not break C_ADDCON2 when S bit is set
- if (p.As == AADDSW || p.As == ASUBSW) && ra0 == C_ADDCON2 {
- ra0 = C_LCON
- }
- a1 = ra0 + 1
- p.From.Class = int8(a1)
- }
- if isANDWop(p.As) && a0 != C_BITCON {
- // For 32-bit logical instruction with constant,
- // the BITCON test is special in that it looks at
- // the 64-bit which has the high 32-bit as a copy
- // of the low 32-bit. We have handled that and
- // don't pass it to con32class.
- a1 = c.con32class(&p.From) + 1
- p.From.Class = int8(a1)
- }
- if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) {
- a1 = c.con64class(&p.From) + 1
- p.From.Class = int8(a1)
- }
- }
- }
-
- a1--
- a3 := C_NONE + 1
- if p.GetFrom3() != nil {
- a3 = int(p.GetFrom3().Class)
- if a3 == 0 {
- a3 = c.aclass(p.GetFrom3()) + 1
- p.GetFrom3().Class = int8(a3)
- }
- }
-
- a3--
- a4 := int(p.To.Class)
- if a4 == 0 {
- a4 = c.aclass(&p.To) + 1
- p.To.Class = int8(a4)
- }
-
- a4--
- a2 := C_NONE
- if p.Reg != 0 {
- a2 = rclass(p.Reg)
- }
-
- if false {
- fmt.Printf("oplook %v %d %d %d %d\n", p.As, a1, a2, a3, a4)
- fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
- }
-
- ops := oprange[p.As&obj.AMask]
- c1 := &xcmp[a1]
- c2 := &xcmp[a2]
- c3 := &xcmp[a3]
- c4 := &xcmp[a4]
- c5 := &xcmp[p.Scond>>5]
- for i := range ops {
- op := &ops[i]
- if (int(op.a2) == a2 || c2[op.a2]) && c5[op.scond>>5] && c1[op.a1] && c3[op.a3] && c4[op.a4] {
- p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
- return op
- }
- }
-
- c.ctxt.Diag("illegal combination: %v %v %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4), p.From.Type, p.To.Type)
- // Turn illegal instruction into an UNDEF, avoid crashing in asmout
- return &Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 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 || b == C_ABCON0 {
- return true
- }
-
- case C_ADDCON:
- if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON || b == C_AMCON {
- return true
- }
-
- case C_BITCON:
- if b == C_ABCON0 || b == C_ABCON || b == C_MBCON {
- return true
- }
-
- case C_MOVCON:
- if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_AMCON {
- return true
- }
-
- case C_ADDCON2:
- if b == C_ZCON || b == C_ADDCON || 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_ABCON0 || b == C_MBCON || b == C_MOVCON || b == C_ADDCON2 || b == C_AMCON {
- return true
- }
-
- case C_MOVCON2:
- return cmp(C_LCON, b)
-
- case C_VCON:
- return cmp(C_LCON, b)
-
- case C_LACON:
- if b == C_AACON || b == C_AACON2 {
- 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_NSAUTO_4:
- if b == C_NSAUTO_8 {
- return true
- }
-
- case C_NSAUTO:
- switch b {
- case C_NSAUTO_4, C_NSAUTO_8:
- return true
- }
-
- case C_NPAUTO:
- switch b {
- case C_NSAUTO_8:
- return true
- }
-
- case C_NAUTO4K:
- switch b {
- case C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO:
- return true
- }
-
- case C_PSAUTO_8:
- if b == C_ZAUTO {
- return true
- }
-
- case C_PSAUTO_4:
- switch b {
- case C_ZAUTO, C_PSAUTO_8:
- return true
- }
-
- case C_PSAUTO:
- switch b {
- case C_ZAUTO, C_PSAUTO_8, C_PSAUTO_4:
- return true
- }
-
- case C_PPAUTO:
- switch b {
- case C_ZAUTO, C_PSAUTO_8:
- return true
- }
-
- case C_UAUTO4K:
- switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
- C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
- return true
- }
-
- case C_UAUTO8K:
- switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
- return true
- }
-
- case C_UAUTO16K:
- switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
- return true
- }
-
- case C_UAUTO32K:
- switch b {
- case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
- C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
- return true
- }
-
- case C_LAUTO:
- switch b {
- case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO,
- C_NAUTO4K, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
- C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8,
- C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8,
- C_UAUTO16K, C_UAUTO16K_8,
- C_UAUTO32K:
- return true
- }
-
- case C_NSOREG_4:
- if b == C_NSOREG_8 {
- return true
- }
-
- case C_NSOREG:
- switch b {
- case C_NSOREG_4, C_NSOREG_8:
- return true
- }
-
- case C_NPOREG:
- switch b {
- case C_NSOREG_8:
- return true
- }
-
- case C_NOREG4K:
- switch b {
- case C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG:
- return true
- }
-
- case C_PSOREG_4:
- switch b {
- case C_ZOREG, C_PSOREG_8:
- return true
- }
-
- case C_PSOREG:
- switch b {
- case C_ZOREG, C_PSOREG_8, C_PSOREG_4:
- return true
- }
-
- case C_PPOREG:
- switch b {
- case C_ZOREG, C_PSOREG_8:
- return true
- }
-
- case C_UOREG4K:
- switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
- return true
- }
-
- case C_UOREG8K:
- switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
- C_UOREG8K_4, C_UOREG8K_8:
- return true
- }
-
- case C_UOREG16K:
- switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4,
- C_UOREG8K_8, C_UOREG16K_8:
- return true
- }
-
- case C_UOREG32K:
- switch b {
- case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
- C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
- return true
- }
-
- case C_LOREG:
- switch b {
- case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG,
- C_NOREG4K, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG,
- C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
- C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8,
- C_UOREG16K, C_UOREG16K_8,
- C_UOREG32K:
- return true
- }
-
- 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]
- if p1.as != p2.as {
- return p1.as < p2.as
- }
- if p1.a1 != p2.a1 {
- return p1.a1 < p2.a1
- }
- if p1.a2 != p2.a2 {
- return p1.a2 < p2.a2
- }
- if p1.a3 != p2.a3 {
- return p1.a3 < p2.a3
- }
- if p1.a4 != p2.a4 {
- return p1.a4 < p2.a4
- }
- if p1.scond != p2.scond {
- return p1.scond < p2.scond
- }
- return false
-}
-
-func oprangeset(a obj.As, t []Optab) {
- oprange[a&obj.AMask] = t
-}
-
-func buildop(ctxt *obj.Link) {
- if oprange[AAND&obj.AMask] != nil {
- // Already initialized; stop now.
- // This happens in the cmd/asm tests,
- // each of which re-initializes the arch.
- return
- }
-
- var n int
- for i := 0; i < C_GOK; i++ {
- for n = 0; n < C_GOK; n++ {
- if cmp(n, i) {
- xcmp[i][n] = true
- }
- }
- }
- for n = 0; optab[n].as != obj.AXXX; n++ {
- }
- sort.Sort(ocmp(optab[:n]))
- for i := 0; i < n; i++ {
- r := optab[i].as
- start := i
- for optab[i].as == r {
- i++
- }
- t := optab[start:i]
- i--
- oprangeset(r, t)
- switch r {
- default:
- ctxt.Diag("unknown op in build: %v", r)
- ctxt.DiagFlush()
- log.Fatalf("bad code")
-
- case AADD:
- oprangeset(AADDS, t)
- oprangeset(ASUB, t)
- oprangeset(ASUBS, t)
- oprangeset(AADDW, t)
- oprangeset(AADDSW, t)
- oprangeset(ASUBW, t)
- oprangeset(ASUBSW, t)
-
- case AAND: /* logical immediate, logical shifted register */
- oprangeset(AANDW, t)
- oprangeset(AEOR, t)
- oprangeset(AEORW, t)
- oprangeset(AORR, t)
- oprangeset(AORRW, t)
- oprangeset(ABIC, t)
- oprangeset(ABICW, t)
- oprangeset(AEON, t)
- oprangeset(AEONW, t)
- oprangeset(AORN, t)
- oprangeset(AORNW, t)
-
- case AANDS: /* logical immediate, logical shifted register, set flags, cannot target RSP */
- oprangeset(AANDSW, t)
- oprangeset(ABICS, t)
- oprangeset(ABICSW, t)
-
- case ANEG:
- oprangeset(ANEGS, t)
- oprangeset(ANEGSW, t)
- oprangeset(ANEGW, t)
-
- case AADC: /* rn=Rd */
- oprangeset(AADCW, t)
-
- oprangeset(AADCS, t)
- oprangeset(AADCSW, t)
- oprangeset(ASBC, t)
- oprangeset(ASBCW, t)
- oprangeset(ASBCS, t)
- oprangeset(ASBCSW, t)
-
- case ANGC: /* rn=REGZERO */
- oprangeset(ANGCW, t)
-
- oprangeset(ANGCS, t)
- oprangeset(ANGCSW, t)
-
- case ACMP:
- oprangeset(ACMPW, t)
- oprangeset(ACMN, t)
- oprangeset(ACMNW, t)
-
- case ATST:
- oprangeset(ATSTW, t)
-
- /* register/register, and shifted */
- case AMVN:
- oprangeset(AMVNW, t)
-
- case AMOVK:
- oprangeset(AMOVKW, t)
- oprangeset(AMOVN, t)
- oprangeset(AMOVNW, t)
- oprangeset(AMOVZ, t)
- oprangeset(AMOVZW, t)
-
- case ASWPD:
- for i := range atomicInstructions {
- oprangeset(i, t)
- }
-
- case ABEQ:
- oprangeset(ABNE, t)
- oprangeset(ABCS, t)
- oprangeset(ABHS, t)
- oprangeset(ABCC, t)
- oprangeset(ABLO, t)
- oprangeset(ABMI, t)
- oprangeset(ABPL, t)
- oprangeset(ABVS, t)
- oprangeset(ABVC, t)
- oprangeset(ABHI, t)
- oprangeset(ABLS, t)
- oprangeset(ABGE, t)
- oprangeset(ABLT, t)
- oprangeset(ABGT, t)
- oprangeset(ABLE, t)
-
- case ALSL:
- oprangeset(ALSLW, t)
- oprangeset(ALSR, t)
- oprangeset(ALSRW, t)
- oprangeset(AASR, t)
- oprangeset(AASRW, t)
- oprangeset(AROR, t)
- oprangeset(ARORW, t)
-
- case ACLS:
- oprangeset(ACLSW, t)
- oprangeset(ACLZ, t)
- oprangeset(ACLZW, t)
- oprangeset(ARBIT, t)
- oprangeset(ARBITW, t)
- oprangeset(AREV, t)
- oprangeset(AREVW, t)
- oprangeset(AREV16, t)
- oprangeset(AREV16W, t)
- oprangeset(AREV32, t)
-
- case ASDIV:
- oprangeset(ASDIVW, t)
- oprangeset(AUDIV, t)
- oprangeset(AUDIVW, t)
- oprangeset(ACRC32B, t)
- oprangeset(ACRC32CB, t)
- oprangeset(ACRC32CH, t)
- oprangeset(ACRC32CW, t)
- oprangeset(ACRC32CX, t)
- oprangeset(ACRC32H, t)
- oprangeset(ACRC32W, t)
- oprangeset(ACRC32X, t)
-
- case AMADD:
- oprangeset(AMADDW, t)
- oprangeset(AMSUB, t)
- oprangeset(AMSUBW, t)
- oprangeset(ASMADDL, t)
- oprangeset(ASMSUBL, t)
- oprangeset(AUMADDL, t)
- oprangeset(AUMSUBL, t)
-
- case AREM:
- oprangeset(AREMW, t)
- oprangeset(AUREM, t)
- oprangeset(AUREMW, t)
-
- case AMUL:
- oprangeset(AMULW, t)
- oprangeset(AMNEG, t)
- oprangeset(AMNEGW, t)
- oprangeset(ASMNEGL, t)
- oprangeset(ASMULL, t)
- oprangeset(ASMULH, t)
- oprangeset(AUMNEGL, t)
- oprangeset(AUMULH, t)
- oprangeset(AUMULL, t)
-
- case AMOVB:
- oprangeset(AMOVBU, t)
-
- case AMOVH:
- oprangeset(AMOVHU, t)
-
- case AMOVW:
- oprangeset(AMOVWU, t)
-
- case ABFM:
- oprangeset(ABFMW, t)
- oprangeset(ASBFM, t)
- oprangeset(ASBFMW, t)
- oprangeset(AUBFM, t)
- oprangeset(AUBFMW, t)
-
- case ABFI:
- oprangeset(ABFIW, t)
- oprangeset(ABFXIL, t)
- oprangeset(ABFXILW, t)
- oprangeset(ASBFIZ, t)
- oprangeset(ASBFIZW, t)
- oprangeset(ASBFX, t)
- oprangeset(ASBFXW, t)
- oprangeset(AUBFIZ, t)
- oprangeset(AUBFIZW, t)
- oprangeset(AUBFX, t)
- oprangeset(AUBFXW, t)
-
- case AEXTR:
- oprangeset(AEXTRW, t)
-
- case ASXTB:
- oprangeset(ASXTBW, t)
- oprangeset(ASXTH, t)
- oprangeset(ASXTHW, t)
- oprangeset(ASXTW, t)
- oprangeset(AUXTB, t)
- oprangeset(AUXTH, t)
- oprangeset(AUXTW, t)
- oprangeset(AUXTBW, t)
- oprangeset(AUXTHW, t)
-
- case ACCMN:
- oprangeset(ACCMNW, t)
- oprangeset(ACCMP, t)
- oprangeset(ACCMPW, t)
-
- case ACSEL:
- oprangeset(ACSELW, t)
- oprangeset(ACSINC, t)
- oprangeset(ACSINCW, t)
- oprangeset(ACSINV, t)
- oprangeset(ACSINVW, t)
- oprangeset(ACSNEG, t)
- oprangeset(ACSNEGW, t)
-
- case ACINC:
- // aliases Rm=Rn, !cond
- oprangeset(ACINCW, t)
- oprangeset(ACINV, t)
- oprangeset(ACINVW, t)
- oprangeset(ACNEG, t)
- oprangeset(ACNEGW, t)
-
- // aliases, Rm=Rn=REGZERO, !cond
- case ACSET:
- oprangeset(ACSETW, t)
-
- oprangeset(ACSETM, t)
- oprangeset(ACSETMW, t)
-
- case AMOVD,
- AMOVBU,
- AB,
- ABL,
- AWORD,
- ADWORD,
- obj.ARET,
- obj.ATEXT:
- break
-
- case ALDP:
- oprangeset(AFLDPD, t)
-
- case ASTP:
- oprangeset(AFSTPD, t)
-
- case ASTPW:
- oprangeset(AFSTPS, t)
-
- case ALDPW:
- oprangeset(ALDPSW, t)
- oprangeset(AFLDPS, t)
-
- case AERET:
- oprangeset(AWFE, t)
- oprangeset(AWFI, t)
- oprangeset(AYIELD, t)
- oprangeset(ASEV, t)
- oprangeset(ASEVL, t)
- oprangeset(ANOOP, t)
- oprangeset(ADRPS, t)
-
- case ACBZ:
- oprangeset(ACBZW, t)
- oprangeset(ACBNZ, t)
- oprangeset(ACBNZW, t)
-
- case ATBZ:
- oprangeset(ATBNZ, t)
-
- case AADR, AADRP:
- break
-
- case ACLREX:
- break
-
- case ASVC:
- oprangeset(AHVC, t)
- oprangeset(AHLT, t)
- oprangeset(ASMC, t)
- oprangeset(ABRK, t)
- oprangeset(ADCPS1, t)
- oprangeset(ADCPS2, t)
- oprangeset(ADCPS3, t)
-
- case AFADDS:
- oprangeset(AFADDD, t)
- oprangeset(AFSUBS, t)
- oprangeset(AFSUBD, t)
- oprangeset(AFMULS, t)
- oprangeset(AFMULD, t)
- oprangeset(AFNMULS, t)
- oprangeset(AFNMULD, t)
- oprangeset(AFDIVS, t)
- oprangeset(AFMAXD, t)
- oprangeset(AFMAXS, t)
- oprangeset(AFMIND, t)
- oprangeset(AFMINS, t)
- oprangeset(AFMAXNMD, t)
- oprangeset(AFMAXNMS, t)
- oprangeset(AFMINNMD, t)
- oprangeset(AFMINNMS, t)
- oprangeset(AFDIVD, t)
-
- case AFMSUBD:
- oprangeset(AFMSUBS, t)
- oprangeset(AFMADDS, t)
- oprangeset(AFMADDD, t)
- oprangeset(AFNMSUBS, t)
- oprangeset(AFNMSUBD, t)
- oprangeset(AFNMADDS, t)
- oprangeset(AFNMADDD, t)
-
- case AFCVTSD:
- oprangeset(AFCVTDS, t)
- oprangeset(AFABSD, t)
- oprangeset(AFABSS, t)
- oprangeset(AFNEGD, t)
- oprangeset(AFNEGS, t)
- oprangeset(AFSQRTD, t)
- oprangeset(AFSQRTS, t)
- oprangeset(AFRINTNS, t)
- oprangeset(AFRINTND, t)
- oprangeset(AFRINTPS, t)
- oprangeset(AFRINTPD, t)
- oprangeset(AFRINTMS, t)
- oprangeset(AFRINTMD, t)
- oprangeset(AFRINTZS, t)
- oprangeset(AFRINTZD, t)
- oprangeset(AFRINTAS, t)
- oprangeset(AFRINTAD, t)
- oprangeset(AFRINTXS, t)
- oprangeset(AFRINTXD, t)
- oprangeset(AFRINTIS, t)
- oprangeset(AFRINTID, t)
- oprangeset(AFCVTDH, t)
- oprangeset(AFCVTHS, t)
- oprangeset(AFCVTHD, t)
- oprangeset(AFCVTSH, t)
-
- case AFCMPS:
- oprangeset(AFCMPD, t)
- oprangeset(AFCMPES, t)
- oprangeset(AFCMPED, t)
-
- case AFCCMPS:
- oprangeset(AFCCMPD, t)
- oprangeset(AFCCMPES, t)
- oprangeset(AFCCMPED, t)
-
- case AFCSELD:
- oprangeset(AFCSELS, t)
-
- case AFMOVS, AFMOVD, AFMOVQ:
- break
-
- case AFCVTZSD:
- oprangeset(AFCVTZSDW, t)
- oprangeset(AFCVTZSS, t)
- oprangeset(AFCVTZSSW, t)
- oprangeset(AFCVTZUD, t)
- oprangeset(AFCVTZUDW, t)
- oprangeset(AFCVTZUS, t)
- oprangeset(AFCVTZUSW, t)
-
- case ASCVTFD:
- oprangeset(ASCVTFS, t)
- oprangeset(ASCVTFWD, t)
- oprangeset(ASCVTFWS, t)
- oprangeset(AUCVTFD, t)
- oprangeset(AUCVTFS, t)
- oprangeset(AUCVTFWD, t)
- oprangeset(AUCVTFWS, t)
-
- case ASYS:
- oprangeset(AAT, t)
- oprangeset(ADC, t)
- oprangeset(AIC, t)
- oprangeset(ATLBI, t)
-
- case ASYSL, AHINT:
- break
-
- case ADMB:
- oprangeset(ADSB, t)
- oprangeset(AISB, t)
-
- case AMRS, AMSR:
- break
-
- case ALDAR:
- oprangeset(ALDARW, t)
- oprangeset(ALDARB, t)
- oprangeset(ALDARH, t)
- fallthrough
-
- case ALDXR:
- oprangeset(ALDXRB, t)
- oprangeset(ALDXRH, t)
- oprangeset(ALDXRW, t)
-
- case ALDAXR:
- oprangeset(ALDAXRB, t)
- oprangeset(ALDAXRH, t)
- oprangeset(ALDAXRW, t)
-
- case ALDXP:
- oprangeset(ALDXPW, t)
- oprangeset(ALDAXP, t)
- oprangeset(ALDAXPW, t)
-
- case ASTLR:
- oprangeset(ASTLRB, t)
- oprangeset(ASTLRH, t)
- oprangeset(ASTLRW, t)
-
- case ASTXR:
- oprangeset(ASTXRB, t)
- oprangeset(ASTXRH, t)
- oprangeset(ASTXRW, t)
-
- case ASTLXR:
- oprangeset(ASTLXRB, t)
- oprangeset(ASTLXRH, t)
- oprangeset(ASTLXRW, t)
-
- case ASTXP:
- oprangeset(ASTLXP, t)
- oprangeset(ASTLXPW, t)
- oprangeset(ASTXPW, t)
-
- case AVADDP:
- oprangeset(AVAND, t)
- oprangeset(AVCMEQ, t)
- oprangeset(AVORR, t)
- oprangeset(AVEOR, t)
- oprangeset(AVBSL, t)
- oprangeset(AVBIT, t)
- oprangeset(AVCMTST, t)
- oprangeset(AVUZP1, t)
- oprangeset(AVUZP2, t)
- oprangeset(AVBIF, t)
-
- case AVADD:
- oprangeset(AVSUB, t)
-
- case AAESD:
- oprangeset(AAESE, t)
- oprangeset(AAESMC, t)
- oprangeset(AAESIMC, t)
- oprangeset(ASHA1SU1, t)
- oprangeset(ASHA256SU0, t)
- oprangeset(ASHA512SU0, t)
-
- case ASHA1C:
- oprangeset(ASHA1P, t)
- oprangeset(ASHA1M, t)
-
- case ASHA256H:
- oprangeset(ASHA256H2, t)
- oprangeset(ASHA512H, t)
- oprangeset(ASHA512H2, t)
-
- case ASHA1SU0:
- oprangeset(ASHA256SU1, t)
- oprangeset(ASHA512SU1, t)
-
- case AVADDV:
- oprangeset(AVUADDLV, t)
-
- case AVFMLA:
- oprangeset(AVFMLS, t)
-
- case AVPMULL:
- oprangeset(AVPMULL2, t)
-
- case AVUSHR:
- oprangeset(AVSHL, t)
- oprangeset(AVSRI, t)
-
- case AVREV32:
- oprangeset(AVCNT, t)
- oprangeset(AVRBIT, t)
- oprangeset(AVREV64, t)
- oprangeset(AVREV16, t)
-
- case AVZIP1:
- oprangeset(AVZIP2, t)
-
- case AVUXTL:
- oprangeset(AVUXTL2, t)
-
- case AVUSHLL:
- oprangeset(AVUSHLL2, t)
-
- case AVLD1R:
- oprangeset(AVLD2, t)
- oprangeset(AVLD2R, t)
- oprangeset(AVLD3, t)
- oprangeset(AVLD3R, t)
- oprangeset(AVLD4, t)
- oprangeset(AVLD4R, t)
-
- case ASHA1H,
- AVCNT,
- AVMOV,
- AVLD1,
- AVST1,
- AVST2,
- AVST3,
- AVST4,
- AVTBL,
- AVDUP,
- AVMOVI,
- APRFM,
- AVEXT:
- break
-
- case obj.ANOP,
- obj.AUNDEF,
- obj.AFUNCDATA,
- obj.APCALIGN,
- obj.APCDATA,
- obj.ADUFFZERO,
- obj.ADUFFCOPY:
- break
- }
- }
-}
-
-// chipfloat7() checks if the immediate constants available in FMOVS/FMOVD instructions.
-// For details of the range of constants available, see
-// http://infocenter.arm.com/help/topic/com.arm.doc.dui0473m/dom1359731199385.html.
-func (c *ctxt7) chipfloat7(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)
-}
-
-// checkUnpredictable checks if the sourse and transfer registers are the same register.
-// ARM64 manual says it is "constrained unpredictable" if the src and dst registers of STP/LDP are same.
-func (c *ctxt7) checkUnpredictable(p *obj.Prog, isload bool, wback bool, rn int16, rt1 int16, rt2 int16) {
- if wback && rn != REGSP && (rn == rt1 || rn == rt2) {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
- if isload && rt1 == rt2 {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
-}
-
-/* checkindex checks if index >= 0 && index <= maxindex */
-func (c *ctxt7) checkindex(p *obj.Prog, index, maxindex int) {
- if index < 0 || index > maxindex {
- c.ctxt.Diag("register element index out of range 0 to %d: %v", maxindex, p)
- }
-}
-
-/* checkoffset checks whether the immediate offset is valid for VLD[1-4].P and VST[1-4].P */
-func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) {
- var offset, list, n, expect int64
- switch as {
- case AVLD1, AVLD2, AVLD3, AVLD4, AVLD1R, AVLD2R, AVLD3R, AVLD4R:
- offset = p.From.Offset
- list = p.To.Offset
- case AVST1, AVST2, AVST3, AVST4:
- offset = p.To.Offset
- list = p.From.Offset
- default:
- c.ctxt.Diag("invalid operation on op %v", p.As)
- }
- opcode := (list >> 12) & 15
- q := (list >> 30) & 1
- size := (list >> 10) & 3
- if offset == 0 {
- return
- }
- switch opcode {
- case 0x7:
- n = 1 // one register
- case 0xa:
- n = 2 // two registers
- case 0x6:
- n = 3 // three registers
- case 0x2:
- n = 4 // four registers
- default:
- c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p)
- }
-
- switch as {
- case AVLD1R, AVLD2R, AVLD3R, AVLD4R:
- if offset != n*(1<<uint(size)) {
- c.ctxt.Diag("invalid post-increment offset: %v", p)
- }
- default:
- if !(q == 0 && offset == n*8) && !(q == 1 && offset == n*16) {
- c.ctxt.Diag("invalid post-increment offset: %v", p)
- }
- }
-
- switch as {
- case AVLD1, AVST1:
- return
- case AVLD1R:
- expect = 1
- case AVLD2, AVST2, AVLD2R:
- expect = 2
- case AVLD3, AVST3, AVLD3R:
- expect = 3
- case AVLD4, AVST4, AVLD4R:
- expect = 4
- }
-
- if expect != n {
- c.ctxt.Diag("expected %d registers, got %d: %v.", expect, n, p)
- }
-}
-
-/* checkShiftAmount checks whether the index shift amount is valid */
-/* for load with register offset instructions */
-func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) {
- var amount int16
- amount = (a.Index >> 5) & 7
- switch p.As {
- case AMOVB, AMOVBU:
- if amount != 0 {
- c.ctxt.Diag("invalid index shift amount: %v", p)
- }
- case AMOVH, AMOVHU:
- if amount != 1 && amount != 0 {
- c.ctxt.Diag("invalid index shift amount: %v", p)
- }
- case AMOVW, AMOVWU, AFMOVS:
- if amount != 2 && amount != 0 {
- c.ctxt.Diag("invalid index shift amount: %v", p)
- }
- case AMOVD, AFMOVD:
- if amount != 3 && amount != 0 {
- c.ctxt.Diag("invalid index shift amount: %v", p)
- }
- default:
- panic("invalid operation")
- }
-}
-
-func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
- var os [5]uint32
- 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:
- c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
-
- case 0: /* pseudo ops */
- break
-
- case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
- o1 = c.oprrr(p, 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 = c.opirr(p, p.As)
-
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- if (o1 & Sbit) == 0 {
- c.ctxt.Diag("ineffective ZR destination\n%v", p)
- }
- rt = REGZERO
- }
-
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- v := int32(c.regoff(&p.From))
- o1 = c.oaddi(p, int32(o1), v, r, rt)
-
- case 3: /* op R<<n[,R],R (shifted register) */
- o1 = c.oprrr(p, p.As)
-
- amount := (p.From.Offset >> 10) & 63
- is64bit := o1 & (1 << 31)
- if is64bit == 0 && amount >= 32 {
- c.ctxt.Diag("shift amount out of range 0 to 31: %v", p)
- }
- o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = REGZERO
- }
- r := int(p.Reg)
- if p.As == AMVN || p.As == AMVNW {
- r = REGZERO
- } else if r == 0 {
- r = rt
- }
- o1 |= (uint32(r&31) << 5) | uint32(rt&31)
-
- case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R; mov $addcon2, R */
- rt := int(p.To.Reg)
- r := int(o.param)
-
- if r == 0 {
- r = REGZERO
- } else if r == REGFROM {
- r = int(p.From.Reg)
- }
- if r == 0 {
- r = REGSP
- }
-
- v := int32(c.regoff(&p.From))
- var op int32
- if v < 0 {
- v = -v
- op = int32(c.opirr(p, ASUB))
- } else {
- op = int32(c.opirr(p, AADD))
- }
-
- if int(o.size) == 8 {
- o1 = c.oaddi(p, op, v&0xfff000, r, REGTMP)
- o2 = c.oaddi(p, op, v&0x000fff, REGTMP, rt)
- break
- }
-
- o1 = c.oaddi(p, op, v, r, rt)
-
- case 5: /* b s; bl s */
- o1 = c.opbra(p, p.As)
-
- if p.To.Sym == nil {
- o1 |= uint32(c.brdist(p, 0, 26, 2))
- break
- }
-
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- rel.Type = objabi.R_CALLARM64
-
- case 6: /* b ,O(R); bl ,O(R) */
- o1 = c.opbrr(p, p.As)
-
- o1 |= uint32(p.To.Reg&31) << 5
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 0
- rel.Type = objabi.R_CALLIND
-
- case 7: /* beq s */
- o1 = c.opbra(p, p.As)
-
- o1 |= uint32(c.brdist(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 = c.opbfm(p, ASBFM, int(v), 63, rf, rt)
-
- case AASRW:
- o1 = c.opbfm(p, ASBFMW, int(v), 31, rf, rt)
-
- case ALSL:
- o1 = c.opbfm(p, AUBFM, int((64-v)&63), int(63-v), rf, rt)
-
- case ALSLW:
- o1 = c.opbfm(p, AUBFMW, int((32-v)&31), int(31-v), rf, rt)
-
- case ALSR:
- o1 = c.opbfm(p, AUBFM, int(v), 63, rf, rt)
-
- case ALSRW:
- o1 = c.opbfm(p, AUBFMW, int(v), 31, rf, rt)
-
- case AROR:
- o1 = c.opextr(p, AEXTR, v, rf, rf, rt)
-
- case ARORW:
- o1 = c.opextr(p, AEXTRW, v, rf, rf, rt)
-
- default:
- c.ctxt.Diag("bad shift $con\n%v", p)
- break
- }
-
- case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
- o1 = c.oprrr(p, 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 = c.opimm(p, p.As)
-
- if p.From.Type != obj.TYPE_NONE {
- o1 |= uint32((p.From.Offset & 0xffff) << 5)
- }
-
- case 11: /* dword */
- c.aclass(&p.To)
-
- o1 = uint32(c.instoffset)
- o2 = uint32(c.instoffset >> 32)
- if p.To.Sym != nil {
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- rel.Type = objabi.R_ADDR
- o2 = 0
- o1 = o2
- }
-
- case 12: /* movT $vcon, reg */
- // NOTE: this case does not use REGTMP. If it ever does,
- // remove the NOTUSETMP flag in optab.
- num := c.omovlconst(p.As, p, &p.From, int(p.To.Reg), os[:])
- if num == 0 {
- c.ctxt.Diag("invalid constant: %v", p)
- }
- o1 = os[0]
- o2 = os[1]
- o3 = os[2]
- o4 = os[3]
-
- case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
- o := uint32(0)
- num := uint8(0)
- cls := oclass(&p.From)
- if isADDWop(p.As) {
- if !cmp(C_LCON, cls) {
- c.ctxt.Diag("illegal combination: %v", p)
- }
- num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
- } else {
- num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
- }
- if num == 0 {
- c.ctxt.Diag("invalid constant: %v", p)
- }
- 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) {
- o = c.opxrrr(p, p.As, false)
- o |= REGTMP & 31 << 16
- o |= LSL0_64
- } else {
- o = c.oprrr(p, p.As)
- o |= REGTMP & 31 << 16 /* shift is 0 */
- }
-
- o |= uint32(r&31) << 5
- o |= uint32(rt & 31)
-
- os[num] = o
- o1 = os[0]
- o2 = os[1]
- o3 = os[2]
- o4 = os[3]
- o5 = os[4]
-
- case 14: /* word */
- if c.aclass(&p.To) == C_ADDR {
- c.ctxt.Diag("address constant needs DWORD\n%v", p)
- }
- o1 = uint32(c.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(c.cursym)
-
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- rel.Type = objabi.R_ADDR
- o1 = 0
- }
-
- case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub/fmadd/fmsub/fnmadd/fnmsub Rm,Ra,Rn,Rd */
- o1 = c.oprrr(p, p.As)
-
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- var r int
- var ra int
- if p.From3Type() == obj.TYPE_REG {
- r = int(p.GetFrom3().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 = c.oprrr(p, 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 = c.oprrr(p, 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 = c.oprrr(p, 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 = c.oprrr(p, p.As)
-
- cond := int(p.From.Reg)
- if cond < COND_EQ || cond > COND_NV {
- c.ctxt.Diag("invalid condition: %v", p)
- } else {
- cond -= COND_EQ
- }
-
- r := int(p.Reg)
- var rf int
- if r != 0 {
- if p.From3Type() == obj.TYPE_NONE {
- /* CINC/CINV/CNEG */
- rf = r
- cond ^= 1
- } else {
- rf = int(p.GetFrom3().Reg) /* CSEL */
- }
- } else {
- /* CSET */
- rf = REGZERO
- r = rf
- cond ^= 1
- }
-
- rt := int(p.To.Reg)
- o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(r&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)
- if cond < COND_EQ || cond > COND_NV {
- c.ctxt.Diag("invalid condition\n%v", p)
- } else {
- cond -= COND_EQ
- }
- var rf int
- if p.GetFrom3().Type == obj.TYPE_REG {
- o1 = c.oprrr(p, p.As)
- rf = int(p.GetFrom3().Reg) /* Rm */
- } else {
- o1 = c.opirr(p, p.As)
- rf = int(p.GetFrom3().Offset & 0x1F)
- }
-
- o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
-
- case 20: /* movT R,O(R) -> strT */
- v := int32(c.regoff(&p.To))
- sz := int32(1 << uint(movesize(p.As)))
-
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
- if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
- o1 = c.olsr9s(p, int32(c.opstr9(p, p.As)), v, r, int(p.From.Reg))
- } else {
- v = int32(c.offsetshift(p, int64(v), int(o.a4)))
- o1 = c.olsr12u(p, int32(c.opstr12(p, p.As)), v, r, int(p.From.Reg))
- }
-
- case 21: /* movT O(R),R -> ldrT */
- v := int32(c.regoff(&p.From))
- sz := int32(1 << uint(movesize(p.As)))
-
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
- if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
- o1 = c.olsr9s(p, int32(c.opldr9(p, p.As)), v, r, int(p.To.Reg))
- } else {
- v = int32(c.offsetshift(p, int64(v), int(o.a1)))
- //print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
- o1 = c.olsr12u(p, int32(c.opldr12(p, p.As)), v, r, int(p.To.Reg))
- }
-
- case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
- if p.From.Reg != REGSP && p.From.Reg == p.To.Reg {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
-
- v := int32(p.From.Offset)
-
- if v < -256 || v > 255 {
- c.ctxt.Diag("offset out of range [-255,254]: %v", p)
- }
- o1 = c.opldrpp(p, 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 */
- if p.To.Reg != REGSP && p.From.Reg == p.To.Reg {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
-
- v := int32(p.To.Offset)
-
- if v < -256 || v > 255 {
- c.ctxt.Diag("offset out of range [-255,254]: %v", p)
- }
- o1 = LD2STR(c.opldrpp(p, 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 := rf == REGSP || rt == REGSP
- if p.As == AMVN || p.As == AMVNW {
- if s {
- c.ctxt.Diag("illegal SP reference\n%v", p)
- }
- o1 = c.oprrr(p, p.As)
- o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
- } else if s {
- o1 = c.opirr(p, p.As)
- o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
- } else {
- o1 = c.oprrr(p, p.As)
- o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
- }
-
- case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */
- o1 = c.oprrr(p, p.As)
-
- rf := int(p.From.Reg)
- if rf == C_NONE {
- rf = int(p.To.Reg)
- }
- rt := int(p.To.Reg)
- o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
-
- case 26: /* negX Rm<<s, Rd -> subX Rm<<s, ZR, Rd */
- o1 = c.oprrr(p, p.As)
-
- o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
- rt := int(p.To.Reg)
- o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
-
- case 27: /* op Rm<<n[,Rn],Rd (extended register) */
- if (p.From.Reg-obj.RBaseARM64)&REG_EXT != 0 {
- amount := (p.From.Reg >> 5) & 7
- if amount > 4 {
- c.ctxt.Diag("shift amount out of range 0 to 4: %v", p)
- }
- o1 = c.opxrrr(p, p.As, true)
- o1 |= c.encRegShiftOrExt(&p.From, p.From.Reg) /* includes reg, op, etc */
- } else {
- o1 = c.opxrrr(p, p.As, false)
- o1 |= uint32(p.From.Reg&31) << 16
- }
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = REGZERO
- }
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- o1 |= (uint32(r&31) << 5) | uint32(rt&31)
-
- case 28: /* logop $vcon, [R], R (64 bit literal) */
- o := uint32(0)
- num := uint8(0)
- cls := oclass(&p.From)
- if isANDWop(p.As) {
- if !cmp(C_LCON, cls) {
- c.ctxt.Diag("illegal combination: %v", p)
- }
- num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
- } else {
- num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
- }
-
- if num == 0 {
- c.ctxt.Diag("invalid constant: %v", p)
- }
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = REGZERO
- }
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- o = c.oprrr(p, p.As)
- o |= REGTMP & 31 << 16 /* shift is 0 */
- o |= uint32(r&31) << 5
- o |= uint32(rt & 31)
-
- os[num] = o
- o1 = os[0]
- o2 = os[1]
- o3 = os[2]
- o4 = os[3]
- o5 = os[4]
-
- case 29: /* op Rn, Rd */
- fc := c.aclass(&p.From)
- tc := c.aclass(&p.To)
- if (p.As == AFMOVD || p.As == AFMOVS) && (fc == C_REG || fc == C_ZCON || tc == C_REG || tc == C_ZCON) {
- // FMOV Rx, Fy or FMOV Fy, Rx
- o1 = FPCVTI(0, 0, 0, 0, 6)
- if p.As == AFMOVD {
- o1 |= 1<<31 | 1<<22 // 64-bit
- }
- if fc == C_REG || fc == C_ZCON {
- o1 |= 1 << 16 // FMOV Rx, Fy
- }
- } else {
- o1 = c.oprrr(p, p.As)
- }
- o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31)
-
- case 30: /* movT R,L(R) -> strT */
- // if offset L can be split into hi+lo, and both fit into instructions, do
- // add $hi, R, Rtmp
- // str R, lo(Rtmp)
- // otherwise, use constant pool
- // mov $L, Rtmp (from constant pool)
- // str R, (R+Rtmp)
- s := movesize(o.as)
- if s < 0 {
- c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
- }
-
- r := int(p.To.Reg)
- if r == 0 {
- r = int(o.param)
- }
-
- v := int32(c.regoff(&p.To))
- var hi int32
- if v < 0 || (v&((1<<uint(s))-1)) != 0 {
- // negative or unaligned offset, use constant pool
- goto storeusepool
- }
-
- hi = v - (v & (0xFFF << uint(s)))
- if hi&0xFFF != 0 {
- c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
- }
- if hi&^0xFFF000 != 0 {
- // hi doesn't fit into an ADD instruction
- goto storeusepool
- }
-
- o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
- o2 = c.olsr12u(p, int32(c.opstr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
- break
-
- storeusepool:
- if r == REGTMP || p.From.Reg == REGTMP {
- c.ctxt.Diag("REGTMP used in large offset store: %v", p)
- }
- o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
- o2 = c.olsxrr(p, int32(c.opstrr(p, p.As, false)), int(p.From.Reg), r, REGTMP)
-
- case 31: /* movT L(R), R -> ldrT */
- // if offset L can be split into hi+lo, and both fit into instructions, do
- // add $hi, R, Rtmp
- // ldr lo(Rtmp), R
- // otherwise, use constant pool
- // mov $L, Rtmp (from constant pool)
- // ldr (R+Rtmp), R
- s := movesize(o.as)
- if s < 0 {
- c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
- }
-
- r := int(p.From.Reg)
- if r == 0 {
- r = int(o.param)
- }
-
- v := int32(c.regoff(&p.From))
- var hi int32
- if v < 0 || (v&((1<<uint(s))-1)) != 0 {
- // negative or unaligned offset, use constant pool
- goto loadusepool
- }
-
- hi = v - (v & (0xFFF << uint(s)))
- if (hi & 0xFFF) != 0 {
- c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
- }
- if hi&^0xFFF000 != 0 {
- // hi doesn't fit into an ADD instruction
- goto loadusepool
- }
-
- o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
- break
-
- loadusepool:
- if r == REGTMP || p.From.Reg == REGTMP {
- c.ctxt.Diag("REGTMP used in large offset load: %v", p)
- }
- o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
- o2 = c.olsxrr(p, int32(c.opldrr(p, p.As, false)), int(p.To.Reg), r, REGTMP)
-
- case 32: /* mov $con, R -> movz/movn */
- o1 = c.omovconst(p.As, p, &p.From, int(p.To.Reg))
-
- case 33: /* movk $uimm16 << pos */
- o1 = c.opirr(p, p.As)
-
- d := p.From.Offset
- s := movcon(d)
- if s < 0 || s >= 4 {
- c.ctxt.Diag("bad constant for MOVK: %#x\n%v", uint64(d), p)
- }
- if (o1&S64) == 0 && s >= 2 {
- c.ctxt.Diag("illegal bit position\n%v", p)
- }
- if ((d >> uint(s*16)) >> 16) != 0 {
- c.ctxt.Diag("requires uimm16\n%v", p)
- }
- rt := int(p.To.Reg)
-
- o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
-
- case 34: /* mov $lacon,R */
- o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
-
- if o1 == 0 {
- break
- }
- o2 = c.opxrrr(p, AADD, false)
- 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 = c.oprrr(p, AMRS)
-
- // SysRegEnc function returns the system register encoding and accessFlags.
- _, v, accessFlags := SysRegEnc(p.From.Reg)
- if v == 0 {
- c.ctxt.Diag("illegal system register:\n%v", p)
- }
- if (o1 & (v &^ (3 << 19))) != 0 {
- c.ctxt.Diag("MRS register value overlap\n%v", p)
- }
- if accessFlags&SR_READ == 0 {
- c.ctxt.Diag("system register is not readable: %v", p)
- }
-
- o1 |= v
- o1 |= uint32(p.To.Reg & 31)
-
- case 36: /* mov R,SPR */
- o1 = c.oprrr(p, AMSR)
-
- // SysRegEnc function returns the system register encoding and accessFlags.
- _, v, accessFlags := SysRegEnc(p.To.Reg)
- if v == 0 {
- c.ctxt.Diag("illegal system register:\n%v", p)
- }
- if (o1 & (v &^ (3 << 19))) != 0 {
- c.ctxt.Diag("MSR register value overlap\n%v", p)
- }
- if accessFlags&SR_WRITE == 0 {
- c.ctxt.Diag("system register is not writable: %v", p)
- }
-
- o1 |= v
- o1 |= uint32(p.From.Reg & 31)
-
- case 37: /* mov $con,PSTATEfield -> MSR [immediate] */
- if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 {
- c.ctxt.Diag("illegal immediate for PSTATE field\n%v", p)
- }
- o1 = c.opirr(p, AMSR)
- o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
- v := uint32(0)
- for i := 0; i < len(pstatefield); i++ {
- if pstatefield[i].reg == p.To.Reg {
- v = pstatefield[i].enc
- break
- }
- }
-
- if v == 0 {
- c.ctxt.Diag("illegal PSTATE field for immediate move\n%v", p)
- }
- o1 |= v
-
- case 38: /* clrex [$imm] */
- o1 = c.opimm(p, 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 = c.opirr(p, p.As)
-
- o1 |= uint32(p.From.Reg & 31)
- o1 |= uint32(c.brdist(p, 0, 19, 2) << 5)
-
- case 40: /* tbz */
- o1 = c.opirr(p, p.As)
-
- v := int32(p.From.Offset)
- if v < 0 || v > 63 {
- c.ctxt.Diag("illegal bit number\n%v", p)
- }
- o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19)
- o1 |= uint32(c.brdist(p, 0, 14, 2) << 5)
- o1 |= uint32(p.Reg & 31)
-
- case 41: /* eret, nop, others with no operands */
- o1 = c.op0(p, p.As)
-
- case 42: /* bfm R,r,s,R */
- o1 = c.opbfm(p, p.As, int(p.From.Offset), int(p.GetFrom3().Offset), int(p.Reg), int(p.To.Reg))
-
- case 43: /* bfm aliases */
- r := int(p.From.Offset)
- s := int(p.GetFrom3().Offset)
- rf := int(p.Reg)
- rt := int(p.To.Reg)
- if rf == 0 {
- rf = rt
- }
- switch p.As {
- case ABFI:
- if r != 0 {
- r = 64 - r
- }
- o1 = c.opbfm(p, ABFM, r, s-1, rf, rt)
-
- case ABFIW:
- if r != 0 {
- r = 32 - r
- }
- o1 = c.opbfm(p, ABFMW, r, s-1, rf, rt)
-
- case ABFXIL:
- o1 = c.opbfm(p, ABFM, r, r+s-1, rf, rt)
-
- case ABFXILW:
- o1 = c.opbfm(p, ABFMW, r, r+s-1, rf, rt)
-
- case ASBFIZ:
- if r != 0 {
- r = 64 - r
- }
- o1 = c.opbfm(p, ASBFM, r, s-1, rf, rt)
-
- case ASBFIZW:
- if r != 0 {
- r = 32 - r
- }
- o1 = c.opbfm(p, ASBFMW, r, s-1, rf, rt)
-
- case ASBFX:
- o1 = c.opbfm(p, ASBFM, r, r+s-1, rf, rt)
-
- case ASBFXW:
- o1 = c.opbfm(p, ASBFMW, r, r+s-1, rf, rt)
-
- case AUBFIZ:
- if r != 0 {
- r = 64 - r
- }
- o1 = c.opbfm(p, AUBFM, r, s-1, rf, rt)
-
- case AUBFIZW:
- if r != 0 {
- r = 32 - r
- }
- o1 = c.opbfm(p, AUBFMW, r, s-1, rf, rt)
-
- case AUBFX:
- o1 = c.opbfm(p, AUBFM, r, r+s-1, rf, rt)
-
- case AUBFXW:
- o1 = c.opbfm(p, AUBFMW, r, r+s-1, rf, rt)
-
- default:
- c.ctxt.Diag("bad bfm alias\n%v", p)
- break
- }
-
- case 44: /* extr $b, Rn, Rm, Rd */
- o1 = c.opextr(p, p.As, int32(p.From.Offset), int(p.GetFrom3().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 := p.As
- if rf == REGZERO {
- as = AMOVWU /* clearer in disassembly */
- }
- switch as {
- case AMOVB, ASXTB:
- o1 = c.opbfm(p, ASBFM, 0, 7, rf, rt)
-
- case AMOVH, ASXTH:
- o1 = c.opbfm(p, ASBFM, 0, 15, rf, rt)
-
- case AMOVW, ASXTW:
- o1 = c.opbfm(p, ASBFM, 0, 31, rf, rt)
-
- case AMOVBU, AUXTB:
- o1 = c.opbfm(p, AUBFM, 0, 7, rf, rt)
-
- case AMOVHU, AUXTH:
- o1 = c.opbfm(p, AUBFM, 0, 15, rf, rt)
-
- case AMOVWU:
- o1 = c.oprrr(p, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
-
- case AUXTW:
- o1 = c.opbfm(p, AUBFM, 0, 31, rf, rt)
-
- case ASXTBW:
- o1 = c.opbfm(p, ASBFMW, 0, 7, rf, rt)
-
- case ASXTHW:
- o1 = c.opbfm(p, ASBFMW, 0, 15, rf, rt)
-
- case AUXTBW:
- o1 = c.opbfm(p, AUBFMW, 0, 7, rf, rt)
-
- case AUXTHW:
- o1 = c.opbfm(p, AUBFMW, 0, 15, rf, rt)
-
- default:
- c.ctxt.Diag("bad sxt %v", as)
- break
- }
-
- case 46: /* cls */
- o1 = c.opbit(p, p.As)
-
- o1 |= uint32(p.From.Reg&31) << 5
- o1 |= uint32(p.To.Reg & 31)
-
- case 47: /* SWPx/LDADDx/LDANDx/LDEORx/LDORx Rs, (Rb), Rt */
- rs := p.From.Reg
- rt := p.RegTo2
- rb := p.To.Reg
-
- fields := atomicInstructions[p.As]
- // rt can't be sp. rt can't be r31 when field A is 0, A bit is the 23rd bit.
- if rt == REG_RSP || (rt == REGZERO && (fields&(1<<23) == 0)) {
- c.ctxt.Diag("illegal destination register: %v\n", p)
- }
- o1 |= fields | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
-
- case 48: /* ADD $C_ADDCON2, Rm, Rd */
- // NOTE: this case does not use REGTMP. If it ever does,
- // remove the NOTUSETMP flag in optab.
- op := c.opirr(p, p.As)
- if op&Sbit != 0 {
- c.ctxt.Diag("can not break addition/subtraction when S bit is set", p)
- }
- rt := int(p.To.Reg)
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0x000fff, r, rt)
- o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0xfff000, rt, rt)
-
- case 50: /* sys/sysl */
- o1 = c.opirr(p, p.As)
-
- if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 {
- c.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 = c.opirr(p, p.As)
-
- if p.From.Type == obj.TYPE_CONST {
- o1 |= uint32((p.From.Offset & 0xF) << 8)
- }
-
- case 52: /* hint */
- o1 = c.opirr(p, p.As)
-
- o1 |= uint32((p.From.Offset & 0x7F) << 5)
-
- case 53: /* and/or/eor/bic/tst/... $bitcon, Rn, Rd */
- a := p.As
- rt := int(p.To.Reg)
- if p.To.Type == obj.TYPE_NONE {
- rt = REGZERO
- }
- r := int(p.Reg)
- if r == 0 {
- r = rt
- }
- mode := 64
- v := uint64(p.From.Offset)
- switch p.As {
- case AANDW, AORRW, AEORW, AANDSW, ATSTW:
- mode = 32
- case ABIC, AORN, AEON, ABICS:
- v = ^v
- case ABICW, AORNW, AEONW, ABICSW:
- v = ^v
- mode = 32
- }
- o1 = c.opirr(p, a)
- o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31)
-
- case 54: /* floating point arith */
- o1 = c.oprrr(p, p.As)
- 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 55: /* floating-point constant */
- var rf int
- o1 = 0xf<<25 | 1<<21 | 1<<12
- rf = c.chipfloat7(p.From.Val.(float64))
- if rf < 0 {
- c.ctxt.Diag("invalid floating-point immediate\n%v", p)
- }
- if p.As == AFMOVD {
- o1 |= 1 << 22
- }
- o1 |= (uint32(rf&0xff) << 13) | uint32(p.To.Reg&31)
-
- case 56: /* floating point compare */
- o1 = c.oprrr(p, p.As)
-
- var rf int
- if p.From.Type == obj.TYPE_FCONST {
- 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 = c.oprrr(p, p.As)
-
- cond := int(p.From.Reg)
- if cond < COND_EQ || cond > COND_NV {
- c.ctxt.Diag("invalid condition\n%v", p)
- } else {
- cond -= COND_EQ
- }
-
- nzcv := int(p.To.Offset)
- if nzcv&^0xF != 0 {
- c.ctxt.Diag("implausible condition\n%v", p)
- }
- rf := int(p.Reg)
- if p.GetFrom3() == nil || p.GetFrom3().Reg < REG_F0 || p.GetFrom3().Reg > REG_F31 {
- c.ctxt.Diag("illegal FCCMP\n%v", p)
- break
- }
- rt := int(p.GetFrom3().Reg)
- o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
-
- case 58: /* ldar/ldarb/ldarh/ldaxp/ldxp/ldaxr/ldxr */
- o1 = c.opload(p, p.As)
-
- o1 |= 0x1F << 16
- o1 |= uint32(p.From.Reg&31) << 5
- if p.As == ALDXP || p.As == ALDXPW || p.As == ALDAXP || p.As == ALDAXPW {
- if int(p.To.Reg) == int(p.To.Offset) {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
- o1 |= uint32(p.To.Offset&31) << 10
- } else {
- o1 |= 0x1F << 10
- }
- o1 |= uint32(p.To.Reg & 31)
-
- case 59: /* stxr/stlxr/stxp/stlxp */
- s := p.RegTo2
- n := p.To.Reg
- t := p.From.Reg
- if isSTLXRop(p.As) {
- if s == t || (s == n && n != REGSP) {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
- } else if isSTXPop(p.As) {
- t2 := int16(p.From.Offset)
- if (s == t || s == t2) || (s == n && n != REGSP) {
- c.ctxt.Diag("constrained unpredictable behavior: %v", p)
- }
- }
- if s == REG_RSP {
- c.ctxt.Diag("illegal destination register: %v\n", p)
- }
- o1 = c.opstore(p, p.As)
-
- if p.RegTo2 != obj.REG_NONE {
- o1 |= uint32(p.RegTo2&31) << 16
- } else {
- o1 |= 0x1F << 16
- }
- if isSTXPop(p.As) {
- o1 |= uint32(p.From.Offset&31) << 10
- }
- o1 |= uint32(p.To.Reg&31)<<5 | uint32(p.From.Reg&31)
-
- case 60: /* adrp label,r */
- d := c.brdist(p, 12, 21, 0)
-
- o1 = ADR(1, uint32(d), uint32(p.To.Reg))
-
- case 61: /* adr label, r */
- d := c.brdist(p, 0, 21, 0)
-
- o1 = ADR(0, uint32(d), uint32(p.To.Reg))
-
- case 62: /* op $movcon, [R], R -> mov $movcon, REGTMP + op REGTMP, [R], R */
- if p.Reg == REGTMP {
- c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
- }
- if isADDWop(p.As) || isANDWop(p.As) {
- o1 = c.omovconst(AMOVW, p, &p.From, REGTMP)
- } else {
- o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
- }
-
- 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.Reg == REGSP || r == REGSP {
- o2 = c.opxrrr(p, p.As, false)
- o2 |= REGTMP & 31 << 16
- o2 |= LSL0_64
- } else {
- o2 = c.oprrr(p, p.As)
- o2 |= REGTMP & 31 << 16 /* shift is 0 */
- }
- o2 |= uint32(r&31) << 5
- o2 |= uint32(rt & 31)
-
- /* reloc ops */
- case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- rel.Type = objabi.R_ADDRARM64
- o3 = c.olsr12u(p, int32(c.opstr12(p, p.As)), 0, REGTMP, int(p.From.Reg))
-
- case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.From.Sym
- rel.Add = p.From.Offset
- rel.Type = objabi.R_ADDRARM64
- o3 = c.olsr12u(p, int32(c.opldr12(p, p.As)), 0, REGTMP, int(p.To.Reg))
-
- case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
- v := int32(c.regoff(&p.From))
- r := int(p.From.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid ldp source: %v\n", p)
- }
- o1 |= c.opldpstp(p, o, v, uint32(r), uint32(p.To.Reg), uint32(p.To.Offset), 1)
-
- case 67: /* stp (r1, r2), O(R)!; stp (r1, r2), (R)O! */
- r := int(p.To.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid stp destination: %v\n", p)
- }
- v := int32(c.regoff(&p.To))
- o1 = c.opldpstp(p, o, v, uint32(r), uint32(p.From.Reg), uint32(p.From.Offset), 0)
-
- case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
- // NOTE: this case does not use REGTMP. If it ever does,
- // remove the NOTUSETMP flag in optab.
- if p.As == AMOVW {
- c.ctxt.Diag("invalid load of 32-bit address: %v", p)
- }
- o1 = ADR(1, 0, uint32(p.To.Reg))
- o2 = c.opirr(p, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.From.Sym
- rel.Add = p.From.Offset
- rel.Type = objabi.R_ADDRARM64
-
- case 69: /* LE model movd $tlsvar, reg -> movz reg, 0 + reloc */
- o1 = c.opirr(p, AMOVZ)
- o1 |= uint32(p.To.Reg & 31)
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 4
- rel.Sym = p.From.Sym
- rel.Type = objabi.R_ARM64_TLS_LE
- if p.From.Offset != 0 {
- c.ctxt.Diag("invalid offset on MOVW $tlsvar")
- }
-
- case 70: /* IE model movd $tlsvar, reg -> adrp REGTMP, 0; ldr reg, [REGTMP, #0] + relocs */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.From.Sym
- rel.Add = 0
- rel.Type = objabi.R_ARM64_TLS_IE
- if p.From.Offset != 0 {
- c.ctxt.Diag("invalid offset on MOVW $tlsvar")
- }
-
- case 71: /* movd sym@GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.From.Sym
- rel.Add = 0
- rel.Type = objabi.R_ARM64_GOTPCREL
-
- case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2 Vm.<T>, Vn.<T>, Vd.<T> */
- af := int((p.From.Reg >> 5) & 15)
- af3 := int((p.Reg >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- if af != af3 || af != at {
- c.ctxt.Diag("operand mismatch: %v", p)
- break
- }
- o1 = c.oprrr(p, p.As)
- rf := int((p.From.Reg) & 31)
- rt := int((p.To.Reg) & 31)
- r := int((p.Reg) & 31)
-
- Q := 0
- size := 0
- switch af {
- case ARNG_16B:
- Q = 1
- size = 0
- case ARNG_2D:
- Q = 1
- size = 3
- case ARNG_2S:
- Q = 0
- size = 2
- case ARNG_4H:
- Q = 0
- size = 1
- case ARNG_4S:
- Q = 1
- size = 2
- case ARNG_8B:
- Q = 0
- size = 0
- case ARNG_8H:
- Q = 1
- size = 1
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- switch p.As {
- case AVORR, AVAND, AVEOR, AVBIT, AVBSL, AVBIF:
- if af != ARNG_16B && af != ARNG_8B {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- case AVFMLA, AVFMLS:
- if af != ARNG_2D && af != ARNG_2S && af != ARNG_4S {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- }
- switch p.As {
- case AVAND, AVEOR:
- size = 0
- case AVBSL:
- size = 1
- case AVORR, AVBIT, AVBIF:
- size = 2
- case AVFMLA, AVFMLS:
- if af == ARNG_2D {
- size = 1
- } else {
- size = 0
- }
- }
-
- o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
-
- case 73: /* vmov V.<T>[index], R */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- imm5 := 0
- o1 = 7<<25 | 0xf<<10
- index := int(p.From.Index)
- switch (p.From.Reg >> 5) & 15 {
- case ARNG_B:
- c.checkindex(p, index, 15)
- imm5 |= 1
- imm5 |= index << 1
- case ARNG_H:
- c.checkindex(p, index, 7)
- imm5 |= 2
- imm5 |= index << 2
- case ARNG_S:
- c.checkindex(p, index, 3)
- imm5 |= 4
- imm5 |= index << 3
- case ARNG_D:
- c.checkindex(p, index, 1)
- imm5 |= 8
- imm5 |= index << 4
- o1 |= 1 << 30
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 74:
- // add $O, R, Rtmp or sub $O, R, Rtmp
- // ldp (Rtmp), (R1, R2)
- r := int(p.From.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid ldp source: %v", p)
- }
- v := int32(c.regoff(&p.From))
-
- if v > 0 {
- if v > 4095 {
- c.ctxt.Diag("offset out of range: %v", p)
- }
- o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
- }
- if v < 0 {
- if v < -4095 {
- c.ctxt.Diag("offset out of range: %v", p)
- }
- o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
- }
- o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
-
- case 75:
- // mov $L, Rtmp (from constant pool)
- // add Rtmp, R, Rtmp
- // ldp (Rtmp), (R1, R2)
- r := int(p.From.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid ldp source: %v", p)
- }
- o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
- o2 = c.opxrrr(p, AADD, false)
- o2 |= (REGTMP & 31) << 16
- o2 |= uint32(r&31) << 5
- o2 |= uint32(REGTMP & 31)
- o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
-
- case 76:
- // add $O, R, Rtmp or sub $O, R, Rtmp
- // stp (R1, R2), (Rtmp)
- r := int(p.To.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid stp destination: %v", p)
- }
- v := int32(c.regoff(&p.To))
- if v > 0 {
- if v > 4095 {
- c.ctxt.Diag("offset out of range: %v", p)
- }
- o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
- }
- if v < 0 {
- if v < -4095 {
- c.ctxt.Diag("offset out of range: %v", p)
- }
- o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
- }
- o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
-
- case 77:
- // mov $L, Rtmp (from constant pool)
- // add Rtmp, R, Rtmp
- // stp (R1, R2), (Rtmp)
- r := int(p.To.Reg)
- if r == obj.REG_NONE {
- r = int(o.param)
- }
- if r == obj.REG_NONE {
- c.ctxt.Diag("invalid stp destination: %v", p)
- }
- o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
- o2 = c.opxrrr(p, AADD, false)
- o2 |= REGTMP & 31 << 16
- o2 |= uint32(r&31) << 5
- o2 |= uint32(REGTMP & 31)
- o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
-
- case 78: /* vmov R, V.<T>[index] */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- imm5 := 0
- o1 = 1<<30 | 7<<25 | 7<<10
- index := int(p.To.Index)
- switch (p.To.Reg >> 5) & 15 {
- case ARNG_B:
- c.checkindex(p, index, 15)
- imm5 |= 1
- imm5 |= index << 1
- case ARNG_H:
- c.checkindex(p, index, 7)
- imm5 |= 2
- imm5 |= index << 2
- case ARNG_S:
- c.checkindex(p, index, 3)
- imm5 |= 4
- imm5 |= index << 3
- case ARNG_D:
- c.checkindex(p, index, 1)
- imm5 |= 8
- imm5 |= index << 4
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 79: /* vdup Vn.<T>[index], Vd.<T> */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- o1 = 7<<25 | 1<<10
- var imm5, Q int
- index := int(p.From.Index)
- switch (p.To.Reg >> 5) & 15 {
- case ARNG_16B:
- c.checkindex(p, index, 15)
- Q = 1
- imm5 = 1
- imm5 |= index << 1
- case ARNG_2D:
- c.checkindex(p, index, 1)
- Q = 1
- imm5 = 8
- imm5 |= index << 4
- case ARNG_2S:
- c.checkindex(p, index, 3)
- Q = 0
- imm5 = 4
- imm5 |= index << 3
- case ARNG_4H:
- c.checkindex(p, index, 7)
- Q = 0
- imm5 = 2
- imm5 |= index << 2
- case ARNG_4S:
- c.checkindex(p, index, 3)
- Q = 1
- imm5 = 4
- imm5 |= index << 3
- case ARNG_8B:
- c.checkindex(p, index, 15)
- Q = 0
- imm5 = 1
- imm5 |= index << 1
- case ARNG_8H:
- c.checkindex(p, index, 7)
- Q = 1
- imm5 = 2
- imm5 |= index << 2
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- o1 |= (uint32(Q&1) << 30) | (uint32(imm5&0x1f) << 16)
- o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 80: /* vmov V.<T>[index], Vn */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- imm5 := 0
- index := int(p.From.Index)
- switch p.As {
- case AVMOV:
- o1 = 1<<30 | 15<<25 | 1<<10
- switch (p.From.Reg >> 5) & 15 {
- case ARNG_B:
- c.checkindex(p, index, 15)
- imm5 |= 1
- imm5 |= index << 1
- case ARNG_H:
- c.checkindex(p, index, 7)
- imm5 |= 2
- imm5 |= index << 2
- case ARNG_S:
- c.checkindex(p, index, 3)
- imm5 |= 4
- imm5 |= index << 3
- case ARNG_D:
- c.checkindex(p, index, 1)
- imm5 |= 8
- imm5 |= index << 4
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- default:
- c.ctxt.Diag("unsupported op %v", p.As)
- }
- o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 81: /* vld[1-4]|vld[1-4]r (Rn), [Vt1.<T>, Vt2.<T>, ...] */
- c.checkoffset(p, p.As)
- r := int(p.From.Reg)
- o1 = c.oprrr(p, p.As)
- if o.scond == C_XPOST {
- o1 |= 1 << 23
- if p.From.Index == 0 {
- // immediate offset variant
- o1 |= 0x1f << 16
- } else {
- // register offset variant
- if isRegShiftOrExt(&p.From) {
- c.ctxt.Diag("invalid extended register op: %v\n", p)
- }
- o1 |= uint32(p.From.Index&0x1f) << 16
- }
- }
- o1 |= uint32(p.To.Offset)
- // cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset
- // add opcode(bit 12-15) for vld1, mask it off if it's not vld1
- o1 = c.maskOpvldvst(p, o1)
- o1 |= uint32(r&31) << 5
-
- case 82: /* vmov Rn, Vd.<T> */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- o1 = 7<<25 | 3<<10
- var imm5, Q uint32
- switch (p.To.Reg >> 5) & 15 {
- case ARNG_16B:
- Q = 1
- imm5 = 1
- case ARNG_2D:
- Q = 1
- imm5 = 8
- case ARNG_2S:
- Q = 0
- imm5 = 4
- case ARNG_4H:
- Q = 0
- imm5 = 2
- case ARNG_4S:
- Q = 1
- imm5 = 4
- case ARNG_8B:
- Q = 0
- imm5 = 1
- case ARNG_8H:
- Q = 1
- imm5 = 2
- default:
- c.ctxt.Diag("invalid arrangement on VMOV Rn, Vd.<T>: %v\n", p)
- }
- o1 |= (Q & 1 << 30) | (imm5 & 0x1f << 16)
- o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 83: /* vmov Vn.<T>, Vd.<T> */
- af := int((p.From.Reg >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- if af != at {
- c.ctxt.Diag("invalid arrangement: %v\n", p)
- }
- o1 = c.oprrr(p, p.As)
- rf := int((p.From.Reg) & 31)
- rt := int((p.To.Reg) & 31)
-
- var Q, size uint32
- switch af {
- case ARNG_8B:
- Q = 0
- size = 0
- case ARNG_16B:
- Q = 1
- size = 0
- case ARNG_4H:
- Q = 0
- size = 1
- case ARNG_8H:
- Q = 1
- size = 1
- case ARNG_2S:
- Q = 0
- size = 2
- case ARNG_4S:
- Q = 1
- size = 2
- default:
- c.ctxt.Diag("invalid arrangement: %v\n", p)
- }
-
- if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- if p.As == AVREV32 && (af == ARNG_2S || af == ARNG_4S) {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- if p.As == AVREV16 && af != ARNG_8B && af != ARNG_16B {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- if p.As == AVMOV {
- o1 |= uint32(rf&31) << 16
- }
-
- if p.As == AVRBIT {
- size = 1
- }
-
- o1 |= (Q&1)<<30 | (size&3)<<22 | uint32(rf&31)<<5 | uint32(rt&31)
-
- case 84: /* vst[1-4] [Vt1.<T>, Vt2.<T>, ...], (Rn) */
- c.checkoffset(p, p.As)
- r := int(p.To.Reg)
- o1 = 3 << 26
- if o.scond == C_XPOST {
- o1 |= 1 << 23
- if p.To.Index == 0 {
- // immediate offset variant
- o1 |= 0x1f << 16
- } else {
- // register offset variant
- if isRegShiftOrExt(&p.To) {
- c.ctxt.Diag("invalid extended register: %v\n", p)
- }
- o1 |= uint32(p.To.Index&31) << 16
- }
- }
- o1 |= uint32(p.From.Offset)
- // cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset
- // add opcode(bit 12-15) for vst1, mask it off if it's not vst1
- o1 = c.maskOpvldvst(p, o1)
- o1 |= uint32(r&31) << 5
-
- case 85: /* vaddv/vuaddlv Vn.<T>, Vd*/
- af := int((p.From.Reg >> 5) & 15)
- o1 = c.oprrr(p, p.As)
- rf := int((p.From.Reg) & 31)
- rt := int((p.To.Reg) & 31)
- Q := 0
- size := 0
- switch af {
- case ARNG_8B:
- Q = 0
- size = 0
- case ARNG_16B:
- Q = 1
- size = 0
- case ARNG_4H:
- Q = 0
- size = 1
- case ARNG_8H:
- Q = 1
- size = 1
- case ARNG_4S:
- Q = 1
- size = 2
- default:
- c.ctxt.Diag("invalid arrangement: %v\n", p)
- }
- o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 86: /* vmovi $imm8, Vd.<T>*/
- at := int((p.To.Reg >> 5) & 15)
- r := int(p.From.Offset)
- if r > 255 || r < 0 {
- c.ctxt.Diag("immediate constant out of range: %v\n", p)
- }
- rt := int((p.To.Reg) & 31)
- Q := 0
- switch at {
- case ARNG_8B:
- Q = 0
- case ARNG_16B:
- Q = 1
- default:
- c.ctxt.Diag("invalid arrangement: %v\n", p)
- }
- o1 = 0xf<<24 | 0xe<<12 | 1<<10
- o1 |= (uint32(Q&1) << 30) | (uint32((r>>5)&7) << 16) | (uint32(r&0x1f) << 5) | uint32(rt&31)
-
- case 87: /* stp (r,r), addr(SB) -> adrp + add + stp */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.To.Sym
- rel.Add = p.To.Offset
- rel.Type = objabi.R_ADDRARM64
- o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
-
- case 88: /* ldp addr(SB), (r,r) -> adrp + add + ldp */
- o1 = ADR(1, 0, REGTMP)
- o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
- rel := obj.Addrel(c.cursym)
- rel.Off = int32(c.pc)
- rel.Siz = 8
- rel.Sym = p.From.Sym
- rel.Add = p.From.Offset
- rel.Type = objabi.R_ADDRARM64
- o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
-
- case 89: /* vadd/vsub Vm, Vn, Vd */
- switch p.As {
- case AVADD:
- o1 = 5<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10
-
- case AVSUB:
- o1 = 7<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10
-
- default:
- c.ctxt.Diag("bad opcode: %v\n", p)
- break
- }
-
- 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) | uint32(rt&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
-
- case 91: /* prfm imm(Rn), <prfop | $imm5> */
- imm := uint32(p.From.Offset)
- r := p.From.Reg
- v := uint32(0xff)
- if p.To.Type == obj.TYPE_CONST {
- v = uint32(p.To.Offset)
- if v > 31 {
- c.ctxt.Diag("illegal prefetch operation\n%v", p)
- }
- } else {
- for i := 0; i < len(prfopfield); i++ {
- if prfopfield[i].reg == p.To.Reg {
- v = prfopfield[i].enc
- break
- }
- }
- if v == 0xff {
- c.ctxt.Diag("illegal prefetch operation:\n%v", p)
- }
- }
-
- o1 = c.opldrpp(p, p.As)
- o1 |= (uint32(r&31) << 5) | (uint32((imm>>3)&0xfff) << 10) | (uint32(v & 31))
-
- case 92: /* vmov Vn.<T>[index], Vd.<T>[index] */
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- imm4 := 0
- imm5 := 0
- o1 = 3<<29 | 7<<25 | 1<<10
- index1 := int(p.To.Index)
- index2 := int(p.From.Index)
- if ((p.To.Reg >> 5) & 15) != ((p.From.Reg >> 5) & 15) {
- c.ctxt.Diag("operand mismatch: %v", p)
- }
- switch (p.To.Reg >> 5) & 15 {
- case ARNG_B:
- c.checkindex(p, index1, 15)
- c.checkindex(p, index2, 15)
- imm5 |= 1
- imm5 |= index1 << 1
- imm4 |= index2
- case ARNG_H:
- c.checkindex(p, index1, 7)
- c.checkindex(p, index2, 7)
- imm5 |= 2
- imm5 |= index1 << 2
- imm4 |= index2 << 1
- case ARNG_S:
- c.checkindex(p, index1, 3)
- c.checkindex(p, index2, 3)
- imm5 |= 4
- imm5 |= index1 << 3
- imm4 |= index2 << 2
- case ARNG_D:
- c.checkindex(p, index1, 1)
- c.checkindex(p, index2, 1)
- imm5 |= 8
- imm5 |= index1 << 4
- imm4 |= index2 << 3
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- o1 |= (uint32(imm5&0x1f) << 16) | (uint32(imm4&0xf) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 93: /* vpmull{2} Vm.<T>, Vn.<T>, Vd */
- af := int((p.From.Reg >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- a := int((p.Reg >> 5) & 15)
-
- var Q, size uint32
- if p.As == AVPMULL {
- Q = 0
- } else {
- Q = 1
- }
-
- var fArng int
- switch at {
- case ARNG_8H:
- if Q == 0 {
- fArng = ARNG_8B
- } else {
- fArng = ARNG_16B
- }
- size = 0
- case ARNG_1Q:
- if Q == 0 {
- fArng = ARNG_1D
- } else {
- fArng = ARNG_2D
- }
- size = 3
- default:
- c.ctxt.Diag("invalid arrangement on Vd.<T>: %v", p)
- }
-
- if af != a || af != fArng {
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- o1 = c.oprrr(p, p.As)
- rf := int((p.From.Reg) & 31)
- rt := int((p.To.Reg) & 31)
- r := int((p.Reg) & 31)
-
- o1 |= ((Q & 1) << 30) | ((size & 3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
-
- case 94: /* vext $imm4, Vm.<T>, Vn.<T>, Vd.<T> */
- af := int(((p.GetFrom3().Reg) >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- a := int((p.Reg >> 5) & 15)
- index := int(p.From.Offset)
-
- if af != a || af != at {
- c.ctxt.Diag("invalid arrangement: %v", p)
- break
- }
-
- var Q uint32
- var b int
- if af == ARNG_8B {
- Q = 0
- b = 7
- } else if af == ARNG_16B {
- Q = 1
- b = 15
- } else {
- c.ctxt.Diag("invalid arrangement, should be B8 or B16: %v", p)
- break
- }
-
- if index < 0 || index > b {
- c.ctxt.Diag("illegal offset: %v", p)
- }
-
- o1 = c.opirr(p, p.As)
- rf := int((p.GetFrom3().Reg) & 31)
- rt := int((p.To.Reg) & 31)
- r := int((p.Reg) & 31)
-
- o1 |= ((Q & 1) << 30) | (uint32(r&31) << 16) | (uint32(index&15) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 95: /* vushr $shift, Vn.<T>, Vd.<T> */
- at := int((p.To.Reg >> 5) & 15)
- af := int((p.Reg >> 5) & 15)
- shift := int(p.From.Offset)
-
- if af != at {
- c.ctxt.Diag("invalid arrangement on op Vn.<T>, Vd.<T>: %v", p)
- }
-
- var Q uint32
- var imax, esize int
-
- switch af {
- case ARNG_8B, ARNG_4H, ARNG_2S:
- Q = 0
- case ARNG_16B, ARNG_8H, ARNG_4S, ARNG_2D:
- Q = 1
- default:
- c.ctxt.Diag("invalid arrangement on op Vn.<T>, Vd.<T>: %v", p)
- }
-
- switch af {
- case ARNG_8B, ARNG_16B:
- imax = 15
- esize = 8
- case ARNG_4H, ARNG_8H:
- imax = 31
- esize = 16
- case ARNG_2S, ARNG_4S:
- imax = 63
- esize = 32
- case ARNG_2D:
- imax = 127
- esize = 64
- }
-
- imm := 0
-
- switch p.As {
- case AVUSHR, AVSRI:
- imm = esize*2 - shift
- if imm < esize || imm > imax {
- c.ctxt.Diag("shift out of range: %v", p)
- }
- case AVSHL:
- imm = esize + shift
- if imm > imax {
- c.ctxt.Diag("shift out of range: %v", p)
- }
- default:
- c.ctxt.Diag("invalid instruction %v\n", p)
- }
-
- o1 = c.opirr(p, p.As)
- rt := int((p.To.Reg) & 31)
- rf := int((p.Reg) & 31)
-
- o1 |= ((Q & 1) << 30) | (uint32(imm&127) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 96: /* vst1 Vt1.<T>[index], offset(Rn) */
- af := int((p.From.Reg >> 5) & 15)
- rt := int((p.From.Reg) & 31)
- rf := int((p.To.Reg) & 31)
- r := int(p.To.Index & 31)
- index := int(p.From.Index)
- offset := int32(c.regoff(&p.To))
-
- if o.scond == C_XPOST {
- if (p.To.Index != 0) && (offset != 0) {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- if p.To.Index == 0 && offset == 0 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- }
-
- if offset != 0 {
- r = 31
- }
-
- var Q, S, size int
- var opcode uint32
- switch af {
- case ARNG_B:
- c.checkindex(p, index, 15)
- if o.scond == C_XPOST && offset != 0 && offset != 1 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 3
- S = (index >> 2) & 1
- size = index & 3
- opcode = 0
- case ARNG_H:
- c.checkindex(p, index, 7)
- if o.scond == C_XPOST && offset != 0 && offset != 2 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 2
- S = (index >> 1) & 1
- size = (index & 1) << 1
- opcode = 2
- case ARNG_S:
- c.checkindex(p, index, 3)
- if o.scond == C_XPOST && offset != 0 && offset != 4 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 1
- S = index & 1
- size = 0
- opcode = 4
- case ARNG_D:
- c.checkindex(p, index, 1)
- if o.scond == C_XPOST && offset != 0 && offset != 8 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index
- S = 0
- size = 1
- opcode = 4
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- if o.scond == C_XPOST {
- o1 |= 27 << 23
- } else {
- o1 |= 26 << 23
- }
-
- o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 97: /* vld1 offset(Rn), vt.<T>[index] */
- at := int((p.To.Reg >> 5) & 15)
- rt := int((p.To.Reg) & 31)
- rf := int((p.From.Reg) & 31)
- r := int(p.From.Index & 31)
- index := int(p.To.Index)
- offset := int32(c.regoff(&p.From))
-
- if o.scond == C_XPOST {
- if (p.From.Index != 0) && (offset != 0) {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- if p.From.Index == 0 && offset == 0 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- }
-
- if offset != 0 {
- r = 31
- }
-
- Q := 0
- S := 0
- size := 0
- var opcode uint32
- switch at {
- case ARNG_B:
- c.checkindex(p, index, 15)
- if o.scond == C_XPOST && offset != 0 && offset != 1 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 3
- S = (index >> 2) & 1
- size = index & 3
- opcode = 0
- case ARNG_H:
- c.checkindex(p, index, 7)
- if o.scond == C_XPOST && offset != 0 && offset != 2 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 2
- S = (index >> 1) & 1
- size = (index & 1) << 1
- opcode = 2
- case ARNG_S:
- c.checkindex(p, index, 3)
- if o.scond == C_XPOST && offset != 0 && offset != 4 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index >> 1
- S = index & 1
- size = 0
- opcode = 4
- case ARNG_D:
- c.checkindex(p, index, 1)
- if o.scond == C_XPOST && offset != 0 && offset != 8 {
- c.ctxt.Diag("invalid offset: %v", p)
- }
- Q = index
- S = 0
- size = 1
- opcode = 4
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
-
- if o.scond == C_XPOST {
- o1 |= 110 << 21
- } else {
- o1 |= 106 << 21
- }
-
- o1 |= (uint32(Q&1) << 30) | (uint32(r&31) << 16) | ((opcode & 7) << 13) | (uint32(S&1) << 12) | (uint32(size&3) << 10) | (uint32(rf&31) << 5) | uint32(rt&31)
-
- case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
- if isRegShiftOrExt(&p.From) {
- // extended or shifted offset register.
- c.checkShiftAmount(p, &p.From)
-
- o1 = c.opldrr(p, p.As, true)
- o1 |= c.encRegShiftOrExt(&p.From, p.From.Index) /* includes reg, op, etc */
- } else {
- // (Rn)(Rm), no extension or shift.
- o1 = c.opldrr(p, p.As, false)
- o1 |= uint32(p.From.Index&31) << 16
- }
- o1 |= uint32(p.From.Reg&31) << 5
- rt := int(p.To.Reg)
- o1 |= uint32(rt & 31)
-
- case 99: /* MOVD Rt, (Rn)(Rm.SXTW[<<amount]) */
- if isRegShiftOrExt(&p.To) {
- // extended or shifted offset register.
- c.checkShiftAmount(p, &p.To)
-
- o1 = c.opstrr(p, p.As, true)
- o1 |= c.encRegShiftOrExt(&p.To, p.To.Index) /* includes reg, op, etc */
- } else {
- // (Rn)(Rm), no extension or shift.
- o1 = c.opstrr(p, p.As, false)
- o1 |= uint32(p.To.Index&31) << 16
- }
- o1 |= uint32(p.To.Reg&31) << 5
- rf := int(p.From.Reg)
- o1 |= uint32(rf & 31)
-
- case 100: /* VTBL Vn.<T>, [Vt1.<T>, Vt2.<T>, ...], Vd.<T> */
- af := int((p.From.Reg >> 5) & 15)
- at := int((p.To.Reg >> 5) & 15)
- if af != at {
- c.ctxt.Diag("invalid arrangement: %v\n", p)
- }
- var q, len uint32
- switch af {
- case ARNG_8B:
- q = 0
- case ARNG_16B:
- q = 1
- default:
- c.ctxt.Diag("invalid arrangement: %v", p)
- }
- rf := int(p.From.Reg)
- rt := int(p.To.Reg)
- offset := int(p.GetFrom3().Offset)
- opcode := (offset >> 12) & 15
- switch opcode {
- case 0x7:
- len = 0 // one register
- case 0xa:
- len = 1 // two register
- case 0x6:
- len = 2 // three registers
- case 0x2:
- len = 3 // four registers
- default:
- c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p)
- }
- o1 = q<<30 | 0xe<<24 | len<<13
- o1 |= (uint32(rf&31) << 16) | uint32(offset&31)<<5 | uint32(rt&31)
-
- case 101: // FOMVQ/FMOVD $vcon, Vd -> load from constant pool.
- o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg))
-
- case 102: /* vushll, vushll2, vuxtl, vuxtl2 */
- o1 = c.opirr(p, p.As)
- rf := p.Reg
- af := uint8((p.Reg >> 5) & 15)
- at := uint8((p.To.Reg >> 5) & 15)
- shift := int(p.From.Offset)
- if p.As == AVUXTL || p.As == AVUXTL2 {
- rf = p.From.Reg
- af = uint8((p.From.Reg >> 5) & 15)
- shift = 0
- }
-
- pack := func(q, x, y uint8) uint32 {
- return uint32(q)<<16 | uint32(x)<<8 | uint32(y)
- }
-
- var Q uint8 = uint8(o1>>30) & 1
- var immh, width uint8
- switch pack(Q, af, at) {
- case pack(0, ARNG_8B, ARNG_8H):
- immh, width = 1, 8
- case pack(1, ARNG_16B, ARNG_8H):
- immh, width = 1, 8
- case pack(0, ARNG_4H, ARNG_4S):
- immh, width = 2, 16
- case pack(1, ARNG_8H, ARNG_4S):
- immh, width = 2, 16
- case pack(0, ARNG_2S, ARNG_2D):
- immh, width = 4, 32
- case pack(1, ARNG_4S, ARNG_2D):
- immh, width = 4, 32
- default:
- c.ctxt.Diag("operand mismatch: %v\n", p)
- }
- if !(0 <= shift && shift <= int(width-1)) {
- c.ctxt.Diag("shift amount out of range: %v\n", p)
- }
- o1 |= uint32(immh)<<19 | uint32(shift)<<16 | uint32(rf&31)<<5 | uint32(p.To.Reg&31)
- }
- out[0] = o1
- out[1] = o2
- out[2] = o3
- out[3] = o4
- out[4] = o5
-}
-
-/*
- * basic Rm op Rn -> Rd (using shifted register with 0)
- * also op Rn -> Rt
- * also Rm*Rn op Ra -> Rd
- * also Vm op Vn -> Vd
- */
-func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) 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, ATST:
- return S64 | 3<<29 | 0xA<<24
-
- case AANDSW, ATSTW:
- 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 ASHA512H:
- return 0xCE<<24 | 3<<21 | 8<<12
-
- case ASHA512H2:
- return 0xCE<<24 | 3<<21 | 8<<12 | 4<<8
-
- case ASHA512SU1:
- return 0xCE<<24 | 3<<21 | 8<<12 | 8<<8
-
- case ASHA512SU0:
- return 0xCE<<24 | 3<<22 | 8<<12
-
- 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 AFMADDD:
- return FPOP3S(0, 0, 1, 0, 0)
-
- case AFMADDS:
- return FPOP3S(0, 0, 0, 0, 0)
-
- case AFMSUBD:
- return FPOP3S(0, 0, 1, 0, 1)
-
- case AFMSUBS:
- return FPOP3S(0, 0, 0, 0, 1)
-
- case AFNMADDD:
- return FPOP3S(0, 0, 1, 1, 0)
-
- case AFNMADDS:
- return FPOP3S(0, 0, 0, 1, 0)
-
- case AFNMSUBD:
- return FPOP3S(0, 0, 1, 1, 1)
-
- case AFNMSUBS:
- return FPOP3S(0, 0, 0, 1, 1)
-
- 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)
-
- case AVADD:
- return 7<<25 | 1<<21 | 1<<15 | 1<<10
-
- case AVSUB:
- return 0x17<<25 | 1<<21 | 1<<15 | 1<<10
-
- case AVADDP:
- return 7<<25 | 1<<21 | 1<<15 | 15<<10
-
- case AVAND:
- return 7<<25 | 1<<21 | 7<<10
-
- case AVCMEQ:
- return 1<<29 | 0x71<<21 | 0x23<<10
-
- case AVCNT:
- return 0xE<<24 | 0x10<<17 | 5<<12 | 2<<10
-
- case AVZIP1:
- return 0xE<<24 | 3<<12 | 2<<10
-
- case AVZIP2:
- return 0xE<<24 | 1<<14 | 3<<12 | 2<<10
-
- case AVEOR:
- return 1<<29 | 0x71<<21 | 7<<10
-
- case AVORR:
- return 7<<25 | 5<<21 | 7<<10
-
- case AVREV16:
- return 3<<26 | 2<<24 | 1<<21 | 3<<11
-
- case AVREV32:
- return 11<<26 | 2<<24 | 1<<21 | 1<<11
-
- case AVREV64:
- return 3<<26 | 2<<24 | 1<<21 | 1<<11
-
- case AVMOV:
- return 7<<25 | 5<<21 | 7<<10
-
- case AVADDV:
- return 7<<25 | 3<<20 | 3<<15 | 7<<11
-
- case AVUADDLV:
- return 1<<29 | 7<<25 | 3<<20 | 7<<11
-
- case AVFMLA:
- return 7<<25 | 0<<23 | 1<<21 | 3<<14 | 3<<10
-
- case AVFMLS:
- return 7<<25 | 1<<23 | 1<<21 | 3<<14 | 3<<10
-
- case AVPMULL, AVPMULL2:
- return 0xE<<24 | 1<<21 | 0x38<<10
-
- case AVRBIT:
- return 0x2E<<24 | 1<<22 | 0x10<<17 | 5<<12 | 2<<10
-
- case AVLD1, AVLD2, AVLD3, AVLD4:
- return 3<<26 | 1<<22
-
- case AVLD1R, AVLD3R:
- return 0xD<<24 | 1<<22
-
- case AVLD2R, AVLD4R:
- return 0xD<<24 | 3<<21
-
- case AVBIF:
- return 1<<29 | 7<<25 | 7<<21 | 7<<10
-
- case AVBIT:
- return 1<<29 | 0x75<<21 | 7<<10
-
- case AVBSL:
- return 1<<29 | 0x73<<21 | 7<<10
-
- case AVCMTST:
- return 0xE<<24 | 1<<21 | 0x23<<10
-
- case AVUZP1:
- return 7<<25 | 3<<11
-
- case AVUZP2:
- return 7<<25 | 1<<14 | 3<<11
- }
-
- c.ctxt.Diag("%v: bad rrr %d %v", p, a, a)
- return 0
-}
-
-/*
- * imm -> Rd
- * imm op Rn -> Rd
- */
-func (c *ctxt7) opirr(p *obj.Prog, a obj.As) 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, ABIC:
- return S64 | 0<<29 | 0x24<<23
-
- case AANDW, ABICW:
- return S32 | 0<<29 | 0x24<<23 | 0<<22
-
- case AORR, AORN:
- return S64 | 1<<29 | 0x24<<23
-
- case AORRW, AORNW:
- return S32 | 1<<29 | 0x24<<23 | 0<<22
-
- case AEOR, AEON:
- return S64 | 2<<29 | 0x24<<23
-
- case AEORW, AEONW:
- return S32 | 2<<29 | 0x24<<23 | 0<<22
-
- case AANDS, ABICS, ATST:
- return S64 | 3<<29 | 0x24<<23
-
- case AANDSW, ABICSW, ATSTW:
- 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)
-
- case AVEXT:
- return 0x2E<<24 | 0<<23 | 0<<21 | 0<<15
-
- case AVUSHR:
- return 0x5E<<23 | 1<<10
-
- case AVSHL:
- return 0x1E<<23 | 21<<10
-
- case AVSRI:
- return 0x5E<<23 | 17<<10
-
- case AVUSHLL, AVUXTL:
- return 1<<29 | 15<<24 | 0x29<<10
-
- case AVUSHLL2, AVUXTL2:
- return 3<<29 | 15<<24 | 0x29<<10
- }
-
- c.ctxt.Diag("%v: bad irr %v", p, a)
- return 0
-}
-
-func (c *ctxt7) opbit(p *obj.Prog, a obj.As) 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:
- c.ctxt.Diag("bad bit op\n%v", p)
- return 0
- }
-}
-
-/*
- * add/subtract sign or zero-extended register
- */
-func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 {
- extension := uint32(0)
- if !extend {
- switch a {
- case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS:
- extension = LSL0_64
-
- case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW:
- extension = LSL0_32
- }
- }
-
- switch a {
- case AADD:
- return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case AADDW:
- return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ACMN, AADDS:
- return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ACMNW, AADDSW:
- return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ASUB:
- return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ASUBW:
- return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ACMP, ASUBS:
- return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
-
- case ACMPW, ASUBSW:
- return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
- }
-
- c.ctxt.Diag("bad opxrrr %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opimm(p *obj.Prog, a obj.As) 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)
- }
-
- c.ctxt.Diag("%v: bad imm %v", p, a)
- return 0
-}
-
-func (c *ctxt7) brdist(p *obj.Prog, preshift int, flen int, shift int) int64 {
- v := int64(0)
- t := int64(0)
- q := p.To.Target()
- if q == nil {
- // TODO: don't use brdist for this case, as it isn't a branch.
- // (Calls from omovlit, and maybe adr/adrp opcodes as well.)
- q = p.Pool
- }
- if q != nil {
- v = (q.Pc >> uint(preshift)) - (c.pc >> uint(preshift))
- if (v & ((1 << uint(shift)) - 1)) != 0 {
- c.ctxt.Diag("misaligned label\n%v", p)
- }
- v >>= uint(shift)
- t = int64(1) << uint(flen-1)
- if v < -t || v >= t {
- c.ctxt.Diag("branch too far %#x vs %#x [%p]\n%v\n%v", v, t, c.blitrl, p, q)
- panic("branch too far")
- }
- }
-
- return v & ((t << 1) - 1)
-}
-
-/*
- * pc-relative branches
- */
-func (c *ctxt7) opbra(p *obj.Prog, a obj.As) 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, obj.ADUFFCOPY, ABL:
- return 1<<31 | 5<<26
- }
-
- c.ctxt.Diag("%v: bad bra %v", p, a)
- return 0
-}
-
-func (c *ctxt7) opbrr(p *obj.Prog, a obj.As) uint32 {
- switch a {
- case ABL:
- return OPBLR(1) /* BLR */
-
- case AB:
- return OPBLR(0) /* BR */
-
- case obj.ARET:
- return OPBLR(2) /* RET */
- }
-
- c.ctxt.Diag("%v: bad brr %v", p, a)
- return 0
-}
-
-func (c *ctxt7) op0(p *obj.Prog, a obj.As) 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 ANOOP:
- 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)
- }
-
- c.ctxt.Diag("%v: bad op0 %v", p, a)
- return 0
-}
-
-/*
- * register offset
- */
-func (c *ctxt7) opload(p *obj.Prog, a obj.As) 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
- }
-
- c.ctxt.Diag("bad opload %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opstore(p *obj.Prog, a obj.As) 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(3, 0, 0, 1, 1)
-
- case ASTLXPW:
- return LDSTX(2, 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
- }
-
- c.ctxt.Diag("bad opstore %v\n%v", a, p)
- return 0
-}
-
-/*
- * load/store register (unsigned immediate) C3.3.13
- * these produce 64-bit values (when there's an option)
- */
-func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
- if v < 0 || v >= (1<<12) {
- c.ctxt.Diag("offset out of range: %d\n%v", v, p)
- }
- o |= (v & 0xFFF) << 10
- o |= int32(b&31) << 5
- o |= int32(r & 31)
- return uint32(o)
-}
-
-func (c *ctxt7) opldr12(p *obj.Prog, a obj.As) 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)
- }
-
- c.ctxt.Diag("bad opldr12 %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opstr12(p *obj.Prog, a obj.As) uint32 {
- return LD2STR(c.opldr12(p, a))
-}
-
-/*
- * load/store register (unscaled immediate) C3.3.12
- */
-func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
- if v < -256 || v > 255 {
- c.ctxt.Diag("offset out of range: %d\n%v", v, p)
- }
- o |= (v & 0x1FF) << 12
- o |= int32(b&31) << 5
- o |= int32(r & 31)
- return uint32(o)
-}
-
-func (c *ctxt7) opldr9(p *obj.Prog, a obj.As) 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)
- }
-
- c.ctxt.Diag("bad opldr9 %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) opstr9(p *obj.Prog, a obj.As) uint32 {
- return LD2STR(c.opldr9(p, a))
-}
-
-func (c *ctxt7) opldrpp(p *obj.Prog, a obj.As) 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
-
- case AFMOVS:
- return 2<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
-
- case AFMOVD:
- return 3<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
-
- case APRFM:
- return 0xf9<<24 | 2<<22
-
- }
-
- c.ctxt.Diag("bad opldr %v\n%v", a, p)
- return 0
-}
-
-// olsxrr attaches register operands to a load/store opcode supplied in o.
-// The result either encodes a load of r from (r1+r2) or a store of r to (r1+r2).
-func (c *ctxt7) olsxrr(p *obj.Prog, o int32, r int, r1 int, r2 int) uint32 {
- o |= int32(r1&31) << 5
- o |= int32(r2&31) << 16
- o |= int32(r & 31)
- return uint32(o)
-}
-
-// opldrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
-// for load instruction with register offset.
-// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm).
-func (c *ctxt7) opldrr(p *obj.Prog, a obj.As, extension bool) uint32 {
- OptionS := uint32(0x1a)
- if extension {
- OptionS = uint32(0) // option value and S value have been encoded into p.From.Offset.
- }
- switch a {
- case AMOVD:
- return OptionS<<10 | 0x3<<21 | 0x1f<<27
- case AMOVW:
- return OptionS<<10 | 0x5<<21 | 0x17<<27
- case AMOVWU:
- return OptionS<<10 | 0x3<<21 | 0x17<<27
- case AMOVH:
- return OptionS<<10 | 0x5<<21 | 0x0f<<27
- case AMOVHU:
- return OptionS<<10 | 0x3<<21 | 0x0f<<27
- case AMOVB:
- return OptionS<<10 | 0x5<<21 | 0x07<<27
- case AMOVBU:
- return OptionS<<10 | 0x3<<21 | 0x07<<27
- case AFMOVS:
- return OptionS<<10 | 0x3<<21 | 0x17<<27 | 1<<26
- case AFMOVD:
- return OptionS<<10 | 0x3<<21 | 0x1f<<27 | 1<<26
- }
- c.ctxt.Diag("bad opldrr %v\n%v", a, p)
- return 0
-}
-
-// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
-// for store instruction with register offset.
-// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm).
-func (c *ctxt7) opstrr(p *obj.Prog, a obj.As, extension bool) uint32 {
- OptionS := uint32(0x1a)
- if extension {
- OptionS = uint32(0) // option value and S value have been encoded into p.To.Offset.
- }
- switch a {
- case AMOVD:
- return OptionS<<10 | 0x1<<21 | 0x1f<<27
- case AMOVW, AMOVWU:
- return OptionS<<10 | 0x1<<21 | 0x17<<27
- case AMOVH, AMOVHU:
- return OptionS<<10 | 0x1<<21 | 0x0f<<27
- case AMOVB, AMOVBU:
- return OptionS<<10 | 0x1<<21 | 0x07<<27
- case AFMOVS:
- return OptionS<<10 | 0x1<<21 | 0x17<<27 | 1<<26
- case AFMOVD:
- return OptionS<<10 | 0x1<<21 | 0x1f<<27 | 1<<26
- }
- c.ctxt.Diag("bad opstrr %v\n%v", a, p)
- return 0
-}
-
-func (c *ctxt7) oaddi(p *obj.Prog, o1 int32, v int32, r int, rt int) uint32 {
- if (v & 0xFFF000) != 0 {
- if v&0xFFF != 0 {
- c.ctxt.Diag("%v misuses oaddi", p)
- }
- v >>= 12
- o1 |= 1 << 22
- }
-
- o1 |= ((v & 0xFFF) << 10) | (int32(r&31) << 5) | int32(rt&31)
- return uint32(o1)
-}
-
-/*
- * load a literal value into dr
- */
-func (c *ctxt7) omovlit(as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
- var o1 int32
- if p.Pool == nil { /* not in literal pool */
- c.aclass(a)
- c.ctxt.Logf("omovlit add %d (%#x)\n", c.instoffset, uint64(c.instoffset))
-
- /* TODO: could be clever, and use general constant builder */
- o1 = int32(c.opirr(p, AADD))
-
- v := int32(c.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, w := 0, 0
- switch as {
- case AFMOVS:
- fp = 1
- w = 0 /* 32-bit SIMD/FP */
-
- case AFMOVD:
- fp = 1
- w = 1 /* 64-bit SIMD/FP */
-
- case AFMOVQ:
- fp = 1
- w = 2 /* 128-bit SIMD/FP */
-
- case AMOVD:
- if p.Pool.As == ADWORD {
- w = 1 /* 64-bit */
- } else if p.Pool.To.Offset < 0 {
- w = 2 /* 32-bit, sign-extended to 64-bit */
- } else if p.Pool.To.Offset >= 0 {
- w = 0 /* 32-bit, zero-extended to 64-bit */
- } else {
- c.ctxt.Diag("invalid operand %v in %v", a, p)
- }
-
- case AMOVBU, AMOVHU, AMOVWU:
- w = 0 /* 32-bit, zero-extended to 64-bit */
-
- case AMOVB, AMOVH, AMOVW:
- w = 2 /* 32-bit, sign-extended to 64-bit */
-
- default:
- c.ctxt.Diag("invalid operation %v in %v", as, p)
- }
-
- v := int32(c.brdist(p, 0, 19, 2))
- o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27)
- o1 |= (v & 0x7FFFF) << 5
- o1 |= int32(dr & 31)
- }
-
- return uint32(o1)
-}
-
-// load a constant (MOVCON or BITCON) in a into rt
-func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
- if cls := oclass(a); cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0 {
- // or $bitcon, REGZERO, rt
- mode := 64
- var as1 obj.As
- switch as {
- case AMOVW:
- as1 = AORRW
- mode = 32
- case AMOVD:
- as1 = AORR
- }
- o1 = c.opirr(p, as1)
- o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31)
- return o1
- }
-
- if as == AMOVW {
- d := uint32(a.Offset)
- s := movcon(int64(d))
- if s < 0 || 16*s >= 32 {
- d = ^d
- s = movcon(int64(d))
- if s < 0 || 16*s >= 32 {
- c.ctxt.Diag("impossible 32-bit move wide: %#x\n%v", uint32(a.Offset), p)
- }
- o1 = c.opirr(p, AMOVNW)
- } else {
- o1 = c.opirr(p, AMOVZW)
- }
- o1 |= MOVCONST(int64(d), s, rt)
- }
- if as == AMOVD {
- d := a.Offset
- s := movcon(d)
- if s < 0 || 16*s >= 64 {
- d = ^d
- s = movcon(d)
- if s < 0 || 16*s >= 64 {
- c.ctxt.Diag("impossible 64-bit move wide: %#x\n%v", uint64(a.Offset), p)
- }
- o1 = c.opirr(p, AMOVN)
- } else {
- o1 = c.opirr(p, AMOVZ)
- }
- o1 |= MOVCONST(d, s, rt)
- }
- return o1
-}
-
-// load a 32-bit/64-bit large constant (LCON or VCON) in a.Offset into rt
-// put the instruction sequence in os and return the number of instructions.
-func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uint32) (num uint8) {
- switch as {
- case AMOVW:
- d := uint32(a.Offset)
- // use MOVZW and MOVKW to load a constant to rt
- os[0] = c.opirr(p, AMOVZW)
- os[0] |= MOVCONST(int64(d), 0, rt)
- os[1] = c.opirr(p, AMOVKW)
- os[1] |= MOVCONST(int64(d), 1, rt)
- return 2
-
- case AMOVD:
- d := a.Offset
- dn := ^d
- var immh [4]uint64
- var i int
- zeroCount := int(0)
- negCount := int(0)
- for i = 0; i < 4; i++ {
- immh[i] = uint64((d >> uint(i*16)) & 0xffff)
- if immh[i] == 0 {
- zeroCount++
- } else if immh[i] == 0xffff {
- negCount++
- }
- }
-
- if zeroCount == 4 || negCount == 4 {
- c.ctxt.Diag("the immediate should be MOVCON: %v", p)
- }
- switch {
- case zeroCount == 3:
- // one MOVZ
- for i = 0; i < 4; i++ {
- if immh[i] != 0 {
- os[0] = c.opirr(p, AMOVZ)
- os[0] |= MOVCONST(d, i, rt)
- break
- }
- }
- return 1
-
- case negCount == 3:
- // one MOVN
- for i = 0; i < 4; i++ {
- if immh[i] != 0xffff {
- os[0] = c.opirr(p, AMOVN)
- os[0] |= MOVCONST(dn, i, rt)
- break
- }
- }
- return 1
-
- case zeroCount == 2:
- // one MOVZ and one MOVK
- for i = 0; i < 4; i++ {
- if immh[i] != 0 {
- os[0] = c.opirr(p, AMOVZ)
- os[0] |= MOVCONST(d, i, rt)
- i++
- break
- }
- }
- for ; i < 4; i++ {
- if immh[i] != 0 {
- os[1] = c.opirr(p, AMOVK)
- os[1] |= MOVCONST(d, i, rt)
- }
- }
- return 2
-
- case negCount == 2:
- // one MOVN and one MOVK
- for i = 0; i < 4; i++ {
- if immh[i] != 0xffff {
- os[0] = c.opirr(p, AMOVN)
- os[0] |= MOVCONST(dn, i, rt)
- i++
- break
- }
- }
- for ; i < 4; i++ {
- if immh[i] != 0xffff {
- os[1] = c.opirr(p, AMOVK)
- os[1] |= MOVCONST(d, i, rt)
- }
- }
- return 2
-
- case zeroCount == 1:
- // one MOVZ and two MOVKs
- for i = 0; i < 4; i++ {
- if immh[i] != 0 {
- os[0] = c.opirr(p, AMOVZ)
- os[0] |= MOVCONST(d, i, rt)
- i++
- break
- }
- }
-
- for j := 1; i < 4; i++ {
- if immh[i] != 0 {
- os[j] = c.opirr(p, AMOVK)
- os[j] |= MOVCONST(d, i, rt)
- j++
- }
- }
- return 3
-
- case negCount == 1:
- // one MOVN and two MOVKs
- for i = 0; i < 4; i++ {
- if immh[i] != 0xffff {
- os[0] = c.opirr(p, AMOVN)
- os[0] |= MOVCONST(dn, i, rt)
- i++
- break
- }
- }
-
- for j := 1; i < 4; i++ {
- if immh[i] != 0xffff {
- os[j] = c.opirr(p, AMOVK)
- os[j] |= MOVCONST(d, i, rt)
- j++
- }
- }
- return 3
-
- default:
- // one MOVZ and 3 MOVKs
- os[0] = c.opirr(p, AMOVZ)
- os[0] |= MOVCONST(d, 0, rt)
- for i = 1; i < 4; i++ {
- os[i] = c.opirr(p, AMOVK)
- os[i] |= MOVCONST(d, i, rt)
- }
- return 4
- }
- default:
- return 0
- }
-}
-
-func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
- var b uint32
- o := c.opirr(p, a)
- if (o & (1 << 31)) == 0 {
- b = 32
- } else {
- b = 64
- }
- if r < 0 || uint32(r) >= b {
- c.ctxt.Diag("illegal bit number\n%v", p)
- }
- o |= (uint32(r) & 0x3F) << 16
- if s < 0 || uint32(s) >= b {
- c.ctxt.Diag("illegal bit number\n%v", p)
- }
- o |= (uint32(s) & 0x3F) << 10
- o |= (uint32(rf&31) << 5) | uint32(rt&31)
- return o
-}
-
-func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) uint32 {
- var b uint32
- o := c.opirr(p, a)
- if (o & (1 << 31)) != 0 {
- b = 63
- } else {
- b = 31
- }
- if v < 0 || uint32(v) > b {
- c.ctxt.Diag("illegal bit number\n%v", p)
- }
- o |= uint32(v) << 10
- o |= uint32(rn&31) << 5
- o |= uint32(rm&31) << 16
- o |= uint32(rt & 31)
- return o
-}
-
-/* genrate instruction encoding for LDP/LDPW/LDPSW/STP/STPW */
-func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uint32) uint32 {
- wback := false
- if o.scond == C_XPOST || o.scond == C_XPRE {
- wback = true
- }
- switch p.As {
- case ALDP, ALDPW, ALDPSW:
- c.checkUnpredictable(p, true, wback, p.From.Reg, p.To.Reg, int16(p.To.Offset))
- case ASTP, ASTPW:
- if wback == true {
- c.checkUnpredictable(p, false, true, p.To.Reg, p.From.Reg, int16(p.From.Offset))
- }
- case AFLDPD, AFLDPS:
- c.checkUnpredictable(p, true, false, p.From.Reg, p.To.Reg, int16(p.To.Offset))
- }
- var ret uint32
- // check offset
- switch p.As {
- case AFLDPD, AFSTPD:
- if vo < -512 || vo > 504 || vo%8 != 0 {
- c.ctxt.Diag("invalid offset %v\n", p)
- }
- vo /= 8
- ret = 1<<30 | 1<<26
- case ALDP, ASTP:
- if vo < -512 || vo > 504 || vo%8 != 0 {
- c.ctxt.Diag("invalid offset %v\n", p)
- }
- vo /= 8
- ret = 2 << 30
- case AFLDPS, AFSTPS:
- if vo < -256 || vo > 252 || vo%4 != 0 {
- c.ctxt.Diag("invalid offset %v\n", p)
- }
- vo /= 4
- ret = 1 << 26
- case ALDPW, ASTPW:
- if vo < -256 || vo > 252 || vo%4 != 0 {
- c.ctxt.Diag("invalid offset %v\n", p)
- }
- vo /= 4
- ret = 0
- case ALDPSW:
- if vo < -256 || vo > 252 || vo%4 != 0 {
- c.ctxt.Diag("invalid offset %v\n", p)
- }
- vo /= 4
- ret = 1 << 30
- default:
- c.ctxt.Diag("invalid instruction %v\n", p)
- }
- // check register pair
- switch p.As {
- case AFLDPD, AFLDPS, AFSTPD, AFSTPS:
- if rl < REG_F0 || REG_F31 < rl || rh < REG_F0 || REG_F31 < rh {
- c.ctxt.Diag("invalid register pair %v\n", p)
- }
- case ALDP, ALDPW, ALDPSW:
- if rl < REG_R0 || REG_R30 < rl || rh < REG_R0 || REG_R30 < rh {
- c.ctxt.Diag("invalid register pair %v\n", p)
- }
- case ASTP, ASTPW:
- if rl < REG_R0 || REG_R31 < rl || rh < REG_R0 || REG_R31 < rh {
- c.ctxt.Diag("invalid register pair %v\n", p)
- }
- }
- // other conditional flag bits
- switch o.scond {
- case C_XPOST:
- ret |= 1 << 23
- case C_XPRE:
- ret |= 3 << 23
- default:
- ret |= 2 << 23
- }
- ret |= 5<<27 | (ldp&1)<<22 | uint32(vo&0x7f)<<15 | (rh&31)<<10 | (rbase&31)<<5 | (rl & 31)
- return ret
-}
-
-func (c *ctxt7) maskOpvldvst(p *obj.Prog, o1 uint32) uint32 {
- if p.As == AVLD1 || p.As == AVST1 {
- return o1
- }
-
- o1 &^= 0xf000 // mask out "opcode" field (bit 12-15)
- switch p.As {
- case AVLD1R, AVLD2R:
- o1 |= 0xC << 12
- case AVLD3R, AVLD4R:
- o1 |= 0xE << 12
- case AVLD2, AVST2:
- o1 |= 8 << 12
- case AVLD3, AVST3:
- o1 |= 4 << 12
- case AVLD4, AVST4:
- default:
- c.ctxt.Diag("unsupported instruction:%v\n", p.As)
- }
- return o1
-}
-
-/*
- * size in log2(bytes)
- */
-func movesize(a obj.As) 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
- }
-}
-
-// rm is the Rm register value, o is the extension, amount is the left shift value.
-func roff(rm int16, o uint32, amount int16) uint32 {
- return uint32(rm&31)<<16 | o<<13 | uint32(amount)<<10
-}
-
-// encRegShiftOrExt returns the encoding of shifted/extended register, Rx<<n and Rx.UXTW<<n, etc.
-func (c *ctxt7) encRegShiftOrExt(a *obj.Addr, r int16) uint32 {
- var num, rm int16
- num = (r >> 5) & 7
- rm = r & 31
- switch {
- case REG_UXTB <= r && r < REG_UXTH:
- return roff(rm, 0, num)
- case REG_UXTH <= r && r < REG_UXTW:
- return roff(rm, 1, num)
- case REG_UXTW <= r && r < REG_UXTX:
- if a.Type == obj.TYPE_MEM {
- if num == 0 {
- return roff(rm, 2, 2)
- } else {
- return roff(rm, 2, 6)
- }
- } else {
- return roff(rm, 2, num)
- }
- case REG_UXTX <= r && r < REG_SXTB:
- return roff(rm, 3, num)
- case REG_SXTB <= r && r < REG_SXTH:
- return roff(rm, 4, num)
- case REG_SXTH <= r && r < REG_SXTW:
- return roff(rm, 5, num)
- case REG_SXTW <= r && r < REG_SXTX:
- if a.Type == obj.TYPE_MEM {
- if num == 0 {
- return roff(rm, 6, 2)
- } else {
- return roff(rm, 6, 6)
- }
- } else {
- return roff(rm, 6, num)
- }
- case REG_SXTX <= r && r < REG_SPECIAL:
- if a.Type == obj.TYPE_MEM {
- if num == 0 {
- return roff(rm, 7, 2)
- } else {
- return roff(rm, 7, 6)
- }
- } else {
- return roff(rm, 7, num)
- }
- case REG_LSL <= r && r < (REG_LSL+1<<8):
- return roff(rm, 3, 6)
- default:
- c.ctxt.Diag("unsupported register extension type.")
- }
-
- return 0
-}