podman
7140 строк · 172.8 Кб
1// 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.
2// https://code.google.com/p/ken-cc/source/browse/
3//
4// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6// Portions Copyright © 1997-1999 Vita Nuova Limited
7// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8// Portions Copyright © 2004,2006 Bruce Ellis
9// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11// Portions Copyright © 2009 The Go Authors. All rights reserved.
12//
13// Permission is hereby granted, free of charge, to any person obtaining a copy
14// of this software and associated documentation files (the "Software"), to deal
15// in the Software without restriction, including without limitation the rights
16// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17// copies of the Software, and to permit persons to whom the Software is
18// furnished to do so, subject to the following conditions:
19//
20// The above copyright notice and this permission notice shall be included in
21// all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29// THE SOFTWARE.
30
31package arm64
32
33import (
34"github.com/twitchyliquid64/golang-asm/obj"
35"github.com/twitchyliquid64/golang-asm/objabi"
36"fmt"
37"log"
38"math"
39"sort"
40)
41
42// ctxt7 holds state while assembling a single function.
43// Each function gets a fresh ctxt7.
44// This allows for multiple functions to be safely concurrently assembled.
45type ctxt7 struct {
46ctxt *obj.Link
47newprog obj.ProgAlloc
48cursym *obj.LSym
49blitrl *obj.Prog
50elitrl *obj.Prog
51autosize int32
52extrasize int32
53instoffset int64
54pc int64
55pool struct {
56start uint32
57size uint32
58}
59}
60
61const (
62funcAlign = 16
63)
64
65const (
66REGFROM = 1
67)
68
69type Optab struct {
70as obj.As
71a1 uint8
72a2 uint8
73a3 uint8
74a4 uint8
75type_ int8
76size int8
77param int16
78flag int8
79scond uint16
80}
81
82func IsAtomicInstruction(as obj.As) bool {
83_, ok := atomicInstructions[as]
84return ok
85}
86
87// known field values of an instruction.
88var atomicInstructions = map[obj.As]uint32{
89ALDADDAD: 3<<30 | 0x1c5<<21 | 0x00<<10,
90ALDADDAW: 2<<30 | 0x1c5<<21 | 0x00<<10,
91ALDADDAH: 1<<30 | 0x1c5<<21 | 0x00<<10,
92ALDADDAB: 0<<30 | 0x1c5<<21 | 0x00<<10,
93ALDADDALD: 3<<30 | 0x1c7<<21 | 0x00<<10,
94ALDADDALW: 2<<30 | 0x1c7<<21 | 0x00<<10,
95ALDADDALH: 1<<30 | 0x1c7<<21 | 0x00<<10,
96ALDADDALB: 0<<30 | 0x1c7<<21 | 0x00<<10,
97ALDADDD: 3<<30 | 0x1c1<<21 | 0x00<<10,
98ALDADDW: 2<<30 | 0x1c1<<21 | 0x00<<10,
99ALDADDH: 1<<30 | 0x1c1<<21 | 0x00<<10,
100ALDADDB: 0<<30 | 0x1c1<<21 | 0x00<<10,
101ALDADDLD: 3<<30 | 0x1c3<<21 | 0x00<<10,
102ALDADDLW: 2<<30 | 0x1c3<<21 | 0x00<<10,
103ALDADDLH: 1<<30 | 0x1c3<<21 | 0x00<<10,
104ALDADDLB: 0<<30 | 0x1c3<<21 | 0x00<<10,
105ALDANDAD: 3<<30 | 0x1c5<<21 | 0x04<<10,
106ALDANDAW: 2<<30 | 0x1c5<<21 | 0x04<<10,
107ALDANDAH: 1<<30 | 0x1c5<<21 | 0x04<<10,
108ALDANDAB: 0<<30 | 0x1c5<<21 | 0x04<<10,
109ALDANDALD: 3<<30 | 0x1c7<<21 | 0x04<<10,
110ALDANDALW: 2<<30 | 0x1c7<<21 | 0x04<<10,
111ALDANDALH: 1<<30 | 0x1c7<<21 | 0x04<<10,
112ALDANDALB: 0<<30 | 0x1c7<<21 | 0x04<<10,
113ALDANDD: 3<<30 | 0x1c1<<21 | 0x04<<10,
114ALDANDW: 2<<30 | 0x1c1<<21 | 0x04<<10,
115ALDANDH: 1<<30 | 0x1c1<<21 | 0x04<<10,
116ALDANDB: 0<<30 | 0x1c1<<21 | 0x04<<10,
117ALDANDLD: 3<<30 | 0x1c3<<21 | 0x04<<10,
118ALDANDLW: 2<<30 | 0x1c3<<21 | 0x04<<10,
119ALDANDLH: 1<<30 | 0x1c3<<21 | 0x04<<10,
120ALDANDLB: 0<<30 | 0x1c3<<21 | 0x04<<10,
121ALDEORAD: 3<<30 | 0x1c5<<21 | 0x08<<10,
122ALDEORAW: 2<<30 | 0x1c5<<21 | 0x08<<10,
123ALDEORAH: 1<<30 | 0x1c5<<21 | 0x08<<10,
124ALDEORAB: 0<<30 | 0x1c5<<21 | 0x08<<10,
125ALDEORALD: 3<<30 | 0x1c7<<21 | 0x08<<10,
126ALDEORALW: 2<<30 | 0x1c7<<21 | 0x08<<10,
127ALDEORALH: 1<<30 | 0x1c7<<21 | 0x08<<10,
128ALDEORALB: 0<<30 | 0x1c7<<21 | 0x08<<10,
129ALDEORD: 3<<30 | 0x1c1<<21 | 0x08<<10,
130ALDEORW: 2<<30 | 0x1c1<<21 | 0x08<<10,
131ALDEORH: 1<<30 | 0x1c1<<21 | 0x08<<10,
132ALDEORB: 0<<30 | 0x1c1<<21 | 0x08<<10,
133ALDEORLD: 3<<30 | 0x1c3<<21 | 0x08<<10,
134ALDEORLW: 2<<30 | 0x1c3<<21 | 0x08<<10,
135ALDEORLH: 1<<30 | 0x1c3<<21 | 0x08<<10,
136ALDEORLB: 0<<30 | 0x1c3<<21 | 0x08<<10,
137ALDORAD: 3<<30 | 0x1c5<<21 | 0x0c<<10,
138ALDORAW: 2<<30 | 0x1c5<<21 | 0x0c<<10,
139ALDORAH: 1<<30 | 0x1c5<<21 | 0x0c<<10,
140ALDORAB: 0<<30 | 0x1c5<<21 | 0x0c<<10,
141ALDORALD: 3<<30 | 0x1c7<<21 | 0x0c<<10,
142ALDORALW: 2<<30 | 0x1c7<<21 | 0x0c<<10,
143ALDORALH: 1<<30 | 0x1c7<<21 | 0x0c<<10,
144ALDORALB: 0<<30 | 0x1c7<<21 | 0x0c<<10,
145ALDORD: 3<<30 | 0x1c1<<21 | 0x0c<<10,
146ALDORW: 2<<30 | 0x1c1<<21 | 0x0c<<10,
147ALDORH: 1<<30 | 0x1c1<<21 | 0x0c<<10,
148ALDORB: 0<<30 | 0x1c1<<21 | 0x0c<<10,
149ALDORLD: 3<<30 | 0x1c3<<21 | 0x0c<<10,
150ALDORLW: 2<<30 | 0x1c3<<21 | 0x0c<<10,
151ALDORLH: 1<<30 | 0x1c3<<21 | 0x0c<<10,
152ALDORLB: 0<<30 | 0x1c3<<21 | 0x0c<<10,
153ASWPAD: 3<<30 | 0x1c5<<21 | 0x20<<10,
154ASWPAW: 2<<30 | 0x1c5<<21 | 0x20<<10,
155ASWPAH: 1<<30 | 0x1c5<<21 | 0x20<<10,
156ASWPAB: 0<<30 | 0x1c5<<21 | 0x20<<10,
157ASWPALD: 3<<30 | 0x1c7<<21 | 0x20<<10,
158ASWPALW: 2<<30 | 0x1c7<<21 | 0x20<<10,
159ASWPALH: 1<<30 | 0x1c7<<21 | 0x20<<10,
160ASWPALB: 0<<30 | 0x1c7<<21 | 0x20<<10,
161ASWPD: 3<<30 | 0x1c1<<21 | 0x20<<10,
162ASWPW: 2<<30 | 0x1c1<<21 | 0x20<<10,
163ASWPH: 1<<30 | 0x1c1<<21 | 0x20<<10,
164ASWPB: 0<<30 | 0x1c1<<21 | 0x20<<10,
165ASWPLD: 3<<30 | 0x1c3<<21 | 0x20<<10,
166ASWPLW: 2<<30 | 0x1c3<<21 | 0x20<<10,
167ASWPLH: 1<<30 | 0x1c3<<21 | 0x20<<10,
168ASWPLB: 0<<30 | 0x1c3<<21 | 0x20<<10,
169}
170
171var oprange [ALAST & obj.AMask][]Optab
172
173var xcmp [C_NCLASS][C_NCLASS]bool
174
175const (
176S32 = 0 << 31
177S64 = 1 << 31
178Sbit = 1 << 29
179LSL0_32 = 2 << 13
180LSL0_64 = 3 << 13
181)
182
183func OPDP2(x uint32) uint32 {
184return 0<<30 | 0<<29 | 0xd6<<21 | x<<10
185}
186
187func OPDP3(sf uint32, op54 uint32, op31 uint32, o0 uint32) uint32 {
188return sf<<31 | op54<<29 | 0x1B<<24 | op31<<21 | o0<<15
189}
190
191func OPBcc(x uint32) uint32 {
192return 0x2A<<25 | 0<<24 | 0<<4 | x&15
193}
194
195func OPBLR(x uint32) uint32 {
196/* x=0, JMP; 1, CALL; 2, RET */
197return 0x6B<<25 | 0<<23 | x<<21 | 0x1F<<16 | 0<<10
198}
199
200func SYSOP(l uint32, op0 uint32, op1 uint32, crn uint32, crm uint32, op2 uint32, rt uint32) uint32 {
201return 0x354<<22 | l<<21 | op0<<19 | op1<<16 | crn&15<<12 | crm&15<<8 | op2<<5 | rt
202}
203
204func SYSHINT(x uint32) uint32 {
205return SYSOP(0, 0, 3, 2, 0, x, 0x1F)
206}
207
208func LDSTR12U(sz uint32, v uint32, opc uint32) uint32 {
209return sz<<30 | 7<<27 | v<<26 | 1<<24 | opc<<22
210}
211
212func LDSTR9S(sz uint32, v uint32, opc uint32) uint32 {
213return sz<<30 | 7<<27 | v<<26 | 0<<24 | opc<<22
214}
215
216func LD2STR(o uint32) uint32 {
217return o &^ (3 << 22)
218}
219
220func LDSTX(sz uint32, o2 uint32, l uint32, o1 uint32, o0 uint32) uint32 {
221return sz<<30 | 0x8<<24 | o2<<23 | l<<22 | o1<<21 | o0<<15
222}
223
224func FPCMP(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 {
225return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<14 | 8<<10 | op2
226}
227
228func FPCCMP(m uint32, s uint32, type_ uint32, op uint32) uint32 {
229return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | 1<<10 | op<<4
230}
231
232func FPOP1S(m uint32, s uint32, type_ uint32, op uint32) uint32 {
233return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<15 | 0x10<<10
234}
235
236func FPOP2S(m uint32, s uint32, type_ uint32, op uint32) uint32 {
237return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<12 | 2<<10
238}
239
240func FPOP3S(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 {
241return m<<31 | s<<29 | 0x1F<<24 | type_<<22 | op<<21 | op2<<15
242}
243
244func FPCVTI(sf uint32, s uint32, type_ uint32, rmode uint32, op uint32) uint32 {
245return sf<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | rmode<<19 | op<<16 | 0<<10
246}
247
248func ADR(p uint32, o uint32, rt uint32) uint32 {
249return p<<31 | (o&3)<<29 | 0x10<<24 | ((o>>2)&0x7FFFF)<<5 | rt&31
250}
251
252func OPBIT(x uint32) uint32 {
253return 1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | x<<10
254}
255
256func MOVCONST(d int64, s int, rt int) uint32 {
257return uint32(((d>>uint(s*16))&0xFFFF)<<5) | uint32(s)&3<<21 | uint32(rt&31)
258}
259
260const (
261// Optab.flag
262LFROM = 1 << 0 // p.From uses constant pool
263LTO = 1 << 1 // p.To uses constant pool
264NOTUSETMP = 1 << 2 // p expands to multiple instructions, but does NOT use REGTMP
265)
266
267var optab = []Optab{
268/* struct Optab:
269OPCODE, from, prog->reg, from3, to, type,size,param,flag,scond */
270{obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
271
272/* arithmetic operations */
273{AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
274{AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
275{AADC, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
276{AADC, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
277{ANEG, C_REG, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0},
278{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 25, 4, 0, 0, 0},
279{ANGC, C_REG, C_NONE, C_NONE, C_REG, 17, 4, 0, 0, 0},
280{ACMP, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0},
281{AADD, C_ADDCON, C_RSP, C_NONE, C_RSP, 2, 4, 0, 0, 0},
282{AADD, C_ADDCON, C_NONE, C_NONE, C_RSP, 2, 4, 0, 0, 0},
283{ACMP, C_ADDCON, C_RSP, C_NONE, C_NONE, 2, 4, 0, 0, 0},
284{AADD, C_MOVCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0},
285{AADD, C_MOVCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0},
286{ACMP, C_MOVCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
287{AADD, C_BITCON, C_RSP, C_NONE, C_RSP, 62, 8, 0, 0, 0},
288{AADD, C_BITCON, C_NONE, C_NONE, C_RSP, 62, 8, 0, 0, 0},
289{ACMP, C_BITCON, C_RSP, C_NONE, C_NONE, 62, 8, 0, 0, 0},
290{AADD, C_ADDCON2, C_RSP, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0},
291{AADD, C_ADDCON2, C_NONE, C_NONE, C_RSP, 48, 8, 0, NOTUSETMP, 0},
292{AADD, C_MOVCON2, C_RSP, C_NONE, C_RSP, 13, 12, 0, 0, 0},
293{AADD, C_MOVCON2, C_NONE, C_NONE, C_RSP, 13, 12, 0, 0, 0},
294{AADD, C_MOVCON3, C_RSP, C_NONE, C_RSP, 13, 16, 0, 0, 0},
295{AADD, C_MOVCON3, C_NONE, C_NONE, C_RSP, 13, 16, 0, 0, 0},
296{AADD, C_VCON, C_RSP, C_NONE, C_RSP, 13, 20, 0, 0, 0},
297{AADD, C_VCON, C_NONE, C_NONE, C_RSP, 13, 20, 0, 0, 0},
298{ACMP, C_MOVCON2, C_REG, C_NONE, C_NONE, 13, 12, 0, 0, 0},
299{ACMP, C_MOVCON3, C_REG, C_NONE, C_NONE, 13, 16, 0, 0, 0},
300{ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0},
301{AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
302{AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
303{AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
304{ACMP, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0},
305{ANEG, C_SHIFT, C_NONE, C_NONE, C_REG, 26, 4, 0, 0, 0},
306{AADD, C_REG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0},
307{AADD, C_REG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
308{ACMP, C_REG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0},
309{AADD, C_EXTREG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0},
310{AADD, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
311{AMVN, C_EXTREG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0},
312{ACMP, C_EXTREG, C_RSP, C_NONE, C_NONE, 27, 4, 0, 0, 0},
313{AADD, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
314{AADD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
315{AMUL, C_REG, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
316{AMUL, C_REG, C_NONE, C_NONE, C_REG, 15, 4, 0, 0, 0},
317{AMADD, C_REG, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
318{AREM, C_REG, C_REG, C_NONE, C_REG, 16, 8, 0, 0, 0},
319{AREM, C_REG, C_NONE, C_NONE, C_REG, 16, 8, 0, 0, 0},
320{ASDIV, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
321{ASDIV, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
322
323{AFADDS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
324{AFADDS, C_FREG, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
325{AFMSUBD, C_FREG, C_FREG, C_FREG, C_FREG, 15, 4, 0, 0, 0},
326{AFCMPS, C_FREG, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0},
327{AFCMPS, C_FCON, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0},
328{AVADDP, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
329{AVADD, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
330{AVADD, C_VREG, C_VREG, C_NONE, C_VREG, 89, 4, 0, 0, 0},
331{AVADD, C_VREG, C_NONE, C_NONE, C_VREG, 89, 4, 0, 0, 0},
332{AVADDV, C_ARNG, C_NONE, C_NONE, C_VREG, 85, 4, 0, 0, 0},
333
334/* logical operations */
335{AAND, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
336{AAND, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
337{AANDS, C_REG, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
338{AANDS, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0, 0, 0},
339{ATST, C_REG, C_REG, C_NONE, C_NONE, 1, 4, 0, 0, 0},
340{AAND, C_MBCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
341{AAND, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
342{AANDS, C_MBCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
343{AANDS, C_MBCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
344{ATST, C_MBCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
345{AAND, C_BITCON, C_REG, C_NONE, C_RSP, 53, 4, 0, 0, 0},
346{AAND, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
347{AANDS, C_BITCON, C_REG, C_NONE, C_REG, 53, 4, 0, 0, 0},
348{AANDS, C_BITCON, C_NONE, C_NONE, C_REG, 53, 4, 0, 0, 0},
349{ATST, C_BITCON, C_REG, C_NONE, C_NONE, 53, 4, 0, 0, 0},
350{AAND, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
351{AAND, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
352{AANDS, C_MOVCON, C_REG, C_NONE, C_REG, 62, 8, 0, 0, 0},
353{AANDS, C_MOVCON, C_NONE, C_NONE, C_REG, 62, 8, 0, 0, 0},
354{ATST, C_MOVCON, C_REG, C_NONE, C_NONE, 62, 8, 0, 0, 0},
355{AAND, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
356{AAND, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
357{AAND, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
358{AAND, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
359{AAND, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
360{AAND, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
361{AANDS, C_MOVCON2, C_REG, C_NONE, C_REG, 28, 12, 0, 0, 0},
362{AANDS, C_MOVCON2, C_NONE, C_NONE, C_REG, 28, 12, 0, 0, 0},
363{AANDS, C_MOVCON3, C_REG, C_NONE, C_REG, 28, 16, 0, 0, 0},
364{AANDS, C_MOVCON3, C_NONE, C_NONE, C_REG, 28, 16, 0, 0, 0},
365{AANDS, C_VCON, C_REG, C_NONE, C_REG, 28, 20, 0, 0, 0},
366{AANDS, C_VCON, C_NONE, C_NONE, C_REG, 28, 20, 0, 0, 0},
367{ATST, C_MOVCON2, C_REG, C_NONE, C_NONE, 28, 12, 0, 0, 0},
368{ATST, C_MOVCON3, C_REG, C_NONE, C_NONE, 28, 16, 0, 0, 0},
369{ATST, C_VCON, C_REG, C_NONE, C_NONE, 28, 20, 0, 0, 0},
370{AAND, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
371{AAND, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
372{AANDS, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0},
373{AANDS, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0},
374{ATST, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0},
375{AMOVD, C_RSP, C_NONE, C_NONE, C_RSP, 24, 4, 0, 0, 0},
376{AMVN, C_REG, C_NONE, C_NONE, C_REG, 24, 4, 0, 0, 0},
377{AMOVB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
378{AMOVBU, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
379{AMOVH, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVHU */
380{AMOVW, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVWU */
381/* TODO: MVN C_SHIFT */
382
383/* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */
384{AMOVW, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
385{AMOVD, C_MOVCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
386{AMOVW, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
387{AMOVD, C_BITCON, C_NONE, C_NONE, C_REG, 32, 4, 0, 0, 0},
388{AMOVW, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0},
389{AMOVD, C_MOVCON2, C_NONE, C_NONE, C_REG, 12, 8, 0, NOTUSETMP, 0},
390{AMOVD, C_MOVCON3, C_NONE, C_NONE, C_REG, 12, 12, 0, NOTUSETMP, 0},
391{AMOVD, C_VCON, C_NONE, C_NONE, C_REG, 12, 16, 0, NOTUSETMP, 0},
392
393{AMOVK, C_VCON, C_NONE, C_NONE, C_REG, 33, 4, 0, 0, 0},
394{AMOVD, C_AACON, C_NONE, C_NONE, C_RSP, 4, 4, REGFROM, 0, 0},
395{AMOVD, C_AACON2, C_NONE, C_NONE, C_RSP, 4, 8, REGFROM, 0, 0},
396
397/* load long effective stack address (load int32 offset and add) */
398{AMOVD, C_LACON, C_NONE, C_NONE, C_RSP, 34, 8, REGSP, LFROM, 0},
399
400// Move a large constant to a Vn.
401{AFMOVQ, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
402{AFMOVD, C_VCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
403{AFMOVS, C_LCON, C_NONE, C_NONE, C_VREG, 101, 4, 0, LFROM, 0},
404
405/* jump operations */
406{AB, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
407{ABL, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
408{AB, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
409{ABL, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
410{ABL, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
411{ABL, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
412{obj.ARET, C_NONE, C_NONE, C_NONE, C_REG, 6, 4, 0, 0, 0},
413{obj.ARET, C_NONE, C_NONE, C_NONE, C_ZOREG, 6, 4, 0, 0, 0},
414{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0},
415{ACBZ, C_REG, C_NONE, C_NONE, C_SBRA, 39, 4, 0, 0, 0},
416{ATBZ, C_VCON, C_REG, C_NONE, C_SBRA, 40, 4, 0, 0, 0},
417{AERET, C_NONE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
418
419// get a PC-relative address
420{AADRP, C_SBRA, C_NONE, C_NONE, C_REG, 60, 4, 0, 0, 0},
421{AADR, C_SBRA, C_NONE, C_NONE, C_REG, 61, 4, 0, 0, 0},
422
423{ACLREX, C_NONE, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0},
424{ACLREX, C_NONE, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0},
425{ABFM, C_VCON, C_REG, C_VCON, C_REG, 42, 4, 0, 0, 0},
426{ABFI, C_VCON, C_REG, C_VCON, C_REG, 43, 4, 0, 0, 0},
427{AEXTR, C_VCON, C_REG, C_REG, C_REG, 44, 4, 0, 0, 0},
428{ASXTB, C_REG, C_NONE, C_NONE, C_REG, 45, 4, 0, 0, 0},
429{ACLS, C_REG, C_NONE, C_NONE, C_REG, 46, 4, 0, 0, 0},
430{ALSL, C_VCON, C_REG, C_NONE, C_REG, 8, 4, 0, 0, 0},
431{ALSL, C_VCON, C_NONE, C_NONE, C_REG, 8, 4, 0, 0, 0},
432{ALSL, C_REG, C_NONE, C_NONE, C_REG, 9, 4, 0, 0, 0},
433{ALSL, C_REG, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
434{ASVC, C_VCON, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
435{ASVC, C_NONE, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
436{ADWORD, C_NONE, C_NONE, C_NONE, C_VCON, 11, 8, 0, NOTUSETMP, 0},
437{ADWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 11, 8, 0, NOTUSETMP, 0},
438{ADWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 11, 8, 0, NOTUSETMP, 0},
439{ADWORD, C_NONE, C_NONE, C_NONE, C_LACON, 11, 8, 0, NOTUSETMP, 0},
440{AWORD, C_NONE, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0},
441{AWORD, C_NONE, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0},
442{AWORD, C_NONE, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0},
443{AMOVW, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0},
444{AMOVD, C_VCONADDR, C_NONE, C_NONE, C_REG, 68, 8, 0, NOTUSETMP, 0},
445{AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
446{AMOVBU, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
447{AMOVH, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
448{AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
449{AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
450{AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
451{AMOVBU, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
452{AMOVH, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
453{AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
454{AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 65, 12, 0, 0, 0},
455{AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 71, 8, 0, 0, 0},
456{AMOVD, C_TLS_LE, C_NONE, C_NONE, C_REG, 69, 4, 0, 0, 0},
457{AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 70, 8, 0, 0, 0},
458
459{AFMOVS, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
460{AFMOVS, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0},
461{AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
462{AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0},
463{AFMOVS, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0},
464{AFMOVS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
465{AFMOVD, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0},
466{AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0},
467{AFMOVS, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
468{AFMOVS, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
469{AFMOVD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
470{AFMOVD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
471{AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
472{ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
473{AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
474{AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0},
475{AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0},
476{AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0},
477{AVMOV, C_REG, C_NONE, C_NONE, C_ARNG, 82, 4, 0, 0, 0},
478{AVMOV, C_REG, C_NONE, C_NONE, C_ELEM, 78, 4, 0, 0, 0},
479{AVMOV, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
480{AVDUP, C_ELEM, C_NONE, C_NONE, C_ARNG, 79, 4, 0, 0, 0},
481{AVMOVI, C_ADDCON, C_NONE, C_NONE, C_ARNG, 86, 4, 0, 0, 0},
482{AVFMLA, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
483{AVEXT, C_VCON, C_ARNG, C_ARNG, C_ARNG, 94, 4, 0, 0, 0},
484{AVTBL, C_ARNG, C_NONE, C_LIST, C_ARNG, 100, 4, 0, 0, 0},
485{AVUSHR, C_VCON, C_ARNG, C_NONE, C_ARNG, 95, 4, 0, 0, 0},
486{AVZIP1, C_ARNG, C_ARNG, C_NONE, C_ARNG, 72, 4, 0, 0, 0},
487{AVUSHLL, C_VCON, C_ARNG, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
488{AVUXTL, C_ARNG, C_NONE, C_NONE, C_ARNG, 102, 4, 0, 0, 0},
489
490/* conditional operations */
491{ACSEL, C_COND, C_REG, C_REG, C_REG, 18, 4, 0, 0, 0},
492{ACINC, C_COND, C_REG, C_NONE, C_REG, 18, 4, 0, 0, 0},
493{ACSET, C_COND, C_NONE, C_NONE, C_REG, 18, 4, 0, 0, 0},
494{AFCSELD, C_COND, C_FREG, C_FREG, C_FREG, 18, 4, 0, 0, 0},
495{ACCMN, C_COND, C_REG, C_REG, C_VCON, 19, 4, 0, 0, 0},
496{ACCMN, C_COND, C_REG, C_VCON, C_VCON, 19, 4, 0, 0, 0},
497{AFCCMPS, C_COND, C_FREG, C_FREG, C_VCON, 57, 4, 0, 0, 0},
498
499/* scaled 12-bit unsigned displacement store */
500{AMOVB, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
501{AMOVB, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
502{AMOVBU, C_REG, C_NONE, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
503{AMOVBU, C_REG, C_NONE, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
504{AMOVH, C_REG, C_NONE, C_NONE, C_UAUTO8K, 20, 4, REGSP, 0, 0},
505{AMOVH, C_REG, C_NONE, C_NONE, C_UOREG8K, 20, 4, 0, 0, 0},
506{AMOVW, C_REG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
507{AMOVW, C_REG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
508{AMOVD, C_REG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
509{AMOVD, C_REG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
510
511{AFMOVS, C_FREG, C_NONE, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
512{AFMOVS, C_FREG, C_NONE, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
513{AFMOVD, C_FREG, C_NONE, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
514{AFMOVD, C_FREG, C_NONE, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
515
516/* unscaled 9-bit signed displacement store */
517{AMOVB, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
518{AMOVB, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
519{AMOVBU, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
520{AMOVBU, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
521{AMOVH, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
522{AMOVH, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
523{AMOVW, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
524{AMOVW, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
525{AMOVD, C_REG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
526{AMOVD, C_REG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
527
528{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
529{AFMOVS, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
530{AFMOVD, C_FREG, C_NONE, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
531{AFMOVD, C_FREG, C_NONE, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
532
533/* scaled 12-bit unsigned displacement load */
534{AMOVB, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
535{AMOVB, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
536{AMOVBU, C_UAUTO4K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
537{AMOVBU, C_UOREG4K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
538{AMOVH, C_UAUTO8K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
539{AMOVH, C_UOREG8K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
540{AMOVW, C_UAUTO16K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
541{AMOVW, C_UOREG16K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
542{AMOVD, C_UAUTO32K, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
543{AMOVD, C_UOREG32K, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
544
545{AFMOVS, C_UAUTO16K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
546{AFMOVS, C_UOREG16K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
547{AFMOVD, C_UAUTO32K, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
548{AFMOVD, C_UOREG32K, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
549
550/* unscaled 9-bit signed displacement load */
551{AMOVB, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
552{AMOVB, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
553{AMOVBU, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
554{AMOVBU, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
555{AMOVH, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
556{AMOVH, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
557{AMOVW, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
558{AMOVW, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
559{AMOVD, C_NSAUTO, C_NONE, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
560{AMOVD, C_NSOREG, C_NONE, C_NONE, C_REG, 21, 4, 0, 0, 0},
561
562{AFMOVS, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
563{AFMOVS, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
564{AFMOVD, C_NSAUTO, C_NONE, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
565{AFMOVD, C_NSOREG, C_NONE, C_NONE, C_FREG, 21, 4, 0, 0, 0},
566
567/* long displacement store */
568{AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
569{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
570{AMOVBU, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
571{AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
572{AMOVH, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
573{AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
574{AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
575{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
576{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
577{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
578
579{AFMOVS, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
580{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
581{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
582{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
583
584/* long displacement load */
585{AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
586{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
587{AMOVBU, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
588{AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
589{AMOVH, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
590{AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
591{AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
592{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
593{AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
594{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
595
596{AFMOVS, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
597{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
598{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
599{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
600
601/* pre/post-indexed load (unscaled, signed 9-bit offset) */
602{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
603{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
604{AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
605{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
606{AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
607{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
608{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
609
610{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
611{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
612{AMOVH, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
613{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
614{AMOVBU, C_LOREG, C_NONE, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
615{AFMOVS, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
616{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
617
618/* pre/post-indexed store (unscaled, signed 9-bit offset) */
619{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
620{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
621{AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
622{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
623{AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
624{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
625{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
626
627{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
628{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
629{AMOVH, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
630{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
631{AMOVBU, C_REG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
632{AFMOVS, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
633{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
634
635/* load with shifted or extended register offset */
636{AMOVD, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
637{AMOVW, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
638{AMOVH, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
639{AMOVB, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
640{AMOVBU, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0},
641{AFMOVS, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0},
642{AFMOVD, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0},
643
644/* store with extended register offset */
645{AMOVD, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
646{AMOVW, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
647{AMOVH, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
648{AMOVB, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
649{AFMOVS, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
650{AFMOVD, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0},
651
652/* pre/post-indexed/signed-offset load/store register pair
653(unscaled, signed 10-bit quad-aligned and long offset) */
654{ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
655{ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
656{ALDP, C_NPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
657{ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
658{ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
659{ALDP, C_PPAUTO, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
660{ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
661{ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
662{ALDP, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
663{ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
664{ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
665{ALDP, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
666{ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
667{ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
668{ALDP, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
669{ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
670{ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
671{ALDP, C_NPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
672{ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
673{ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
674{ALDP, C_PPOREG, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
675{ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
676{ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
677{ALDP, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
678{ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
679{ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
680{ALDP, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
681{ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
682{ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
683{ALDP, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
684{ALDP, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
685
686{ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, 0},
687{ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPRE},
688{ASTP, C_PAIR, C_NONE, C_NONE, C_NPAUTO, 67, 4, REGSP, 0, C_XPOST},
689{ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, 0},
690{ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPRE},
691{ASTP, C_PAIR, C_NONE, C_NONE, C_PPAUTO, 67, 4, REGSP, 0, C_XPOST},
692{ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
693{ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
694{ASTP, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
695{ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
696{ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
697{ASTP, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
698{ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
699{ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
700{ASTP, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
701{ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, 0},
702{ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPRE},
703{ASTP, C_PAIR, C_NONE, C_NONE, C_NPOREG, 67, 4, 0, 0, C_XPOST},
704{ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, 0},
705{ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPRE},
706{ASTP, C_PAIR, C_NONE, C_NONE, C_PPOREG, 67, 4, 0, 0, C_XPOST},
707{ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
708{ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
709{ASTP, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
710{ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
711{ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
712{ASTP, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
713{ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
714{ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
715{ASTP, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
716{ASTP, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
717
718// differ from LDP/STP for C_NSAUTO_4/C_PSAUTO_4/C_NSOREG_4/C_PSOREG_4
719{ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
720{ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
721{ALDPW, C_NSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
722{ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, 0},
723{ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPRE},
724{ALDPW, C_PSAUTO_4, C_NONE, C_NONE, C_PAIR, 66, 4, REGSP, 0, C_XPOST},
725{ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
726{ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
727{ALDPW, C_UAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
728{ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, 0},
729{ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPRE},
730{ALDPW, C_NAUTO4K, C_NONE, C_NONE, C_PAIR, 74, 8, REGSP, 0, C_XPOST},
731{ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, 0},
732{ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPRE},
733{ALDPW, C_LAUTO, C_NONE, C_NONE, C_PAIR, 75, 12, REGSP, LFROM, C_XPOST},
734{ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
735{ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
736{ALDPW, C_NSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
737{ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, 0},
738{ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
739{ALDPW, C_PSOREG_4, C_NONE, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
740{ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
741{ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
742{ALDPW, C_UOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
743{ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, 0},
744{ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPRE},
745{ALDPW, C_NOREG4K, C_NONE, C_NONE, C_PAIR, 74, 8, 0, 0, C_XPOST},
746{ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, 0},
747{ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPRE},
748{ALDPW, C_LOREG, C_NONE, C_NONE, C_PAIR, 75, 12, 0, LFROM, C_XPOST},
749{ALDPW, C_ADDR, C_NONE, C_NONE, C_PAIR, 88, 12, 0, 0, 0},
750
751{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, 0},
752{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
753{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
754{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, 0},
755{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPRE},
756{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSAUTO_4, 67, 4, REGSP, 0, C_XPOST},
757{ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, 0},
758{ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPRE},
759{ASTPW, C_PAIR, C_NONE, C_NONE, C_UAUTO4K, 76, 8, REGSP, 0, C_XPOST},
760{ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, 0},
761{ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPRE},
762{ASTPW, C_PAIR, C_NONE, C_NONE, C_NAUTO4K, 76, 12, REGSP, 0, C_XPOST},
763{ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, 0},
764{ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPRE},
765{ASTPW, C_PAIR, C_NONE, C_NONE, C_LAUTO, 77, 12, REGSP, LTO, C_XPOST},
766{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, 0},
767{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPRE},
768{ASTPW, C_PAIR, C_NONE, C_NONE, C_NSOREG_4, 67, 4, 0, 0, C_XPOST},
769{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, 0},
770{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPRE},
771{ASTPW, C_PAIR, C_NONE, C_NONE, C_PSOREG_4, 67, 4, 0, 0, C_XPOST},
772{ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, 0},
773{ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPRE},
774{ASTPW, C_PAIR, C_NONE, C_NONE, C_UOREG4K, 76, 8, 0, 0, C_XPOST},
775{ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, 0},
776{ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPRE},
777{ASTPW, C_PAIR, C_NONE, C_NONE, C_NOREG4K, 76, 8, 0, 0, C_XPOST},
778{ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, 0},
779{ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPRE},
780{ASTPW, C_PAIR, C_NONE, C_NONE, C_LOREG, 77, 12, 0, LTO, C_XPOST},
781{ASTPW, C_PAIR, C_NONE, C_NONE, C_ADDR, 87, 12, 0, 0, 0},
782
783{ASWPD, C_REG, C_NONE, C_NONE, C_ZOREG, 47, 4, 0, 0, 0}, // RegTo2=C_REG
784{ASWPD, C_REG, C_NONE, C_NONE, C_ZAUTO, 47, 4, REGSP, 0, 0}, // RegTo2=C_REG
785{ALDAR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
786{ALDXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
787{ALDAXR, C_ZOREG, C_NONE, C_NONE, C_REG, 58, 4, 0, 0, 0},
788{ALDXP, C_ZOREG, C_NONE, C_NONE, C_PAIR, 58, 4, 0, 0, 0},
789{ASTLR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_NONE
790{ASTXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG
791{ASTLXR, C_REG, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // RegTo2=C_REG
792{ASTXP, C_PAIR, C_NONE, C_NONE, C_ZOREG, 59, 4, 0, 0, 0},
793
794/* VLD[1-4]/VST[1-4] */
795{AVLD1, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0},
796{AVLD1, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
797{AVLD1, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
798{AVLD1R, C_ZOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, 0},
799{AVLD1R, C_LOREG, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
800{AVLD1R, C_ROFF, C_NONE, C_NONE, C_LIST, 81, 4, 0, 0, C_XPOST},
801{AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST},
802{AVLD1, C_ROFF, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, C_XPOST},
803{AVLD1, C_LOREG, C_NONE, C_NONE, C_ELEM, 97, 4, 0, 0, 0},
804{AVST1, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
805{AVST1, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
806{AVST1, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
807{AVST2, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
808{AVST2, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
809{AVST2, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
810{AVST3, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
811{AVST3, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
812{AVST3, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
813{AVST4, C_LIST, C_NONE, C_NONE, C_ZOREG, 84, 4, 0, 0, 0},
814{AVST4, C_LIST, C_NONE, C_NONE, C_LOREG, 84, 4, 0, 0, C_XPOST},
815{AVST4, C_LIST, C_NONE, C_NONE, C_ROFF, 84, 4, 0, 0, C_XPOST},
816{AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, C_XPOST},
817{AVST1, C_ELEM, C_NONE, C_NONE, C_ROFF, 96, 4, 0, 0, C_XPOST},
818{AVST1, C_ELEM, C_NONE, C_NONE, C_LOREG, 96, 4, 0, 0, 0},
819
820/* special */
821{AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0},
822{AMRS, C_SPR, C_NONE, C_NONE, C_REG, 35, 4, 0, 0, 0},
823{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0},
824{AMSR, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0},
825{AMOVD, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
826{AMSR, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
827{APRFM, C_UOREG32K, C_NONE, C_NONE, C_SPR, 91, 4, 0, 0, 0},
828{APRFM, C_UOREG32K, C_NONE, C_NONE, C_LCON, 91, 4, 0, 0, 0},
829{ADMB, C_VCON, C_NONE, C_NONE, C_NONE, 51, 4, 0, 0, 0},
830{AHINT, C_VCON, C_NONE, C_NONE, C_NONE, 52, 4, 0, 0, 0},
831{ASYS, C_VCON, C_NONE, C_NONE, C_NONE, 50, 4, 0, 0, 0},
832{ASYS, C_VCON, C_REG, C_NONE, C_NONE, 50, 4, 0, 0, 0},
833{ASYSL, C_VCON, C_NONE, C_NONE, C_REG, 50, 4, 0, 0, 0},
834
835/* encryption instructions */
836{AAESD, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0}, // for compatibility with old code
837{AAESD, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0}, // recommend using the new one for better readability
838{ASHA1C, C_VREG, C_REG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
839{ASHA1C, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
840{ASHA1H, C_VREG, C_NONE, C_NONE, C_VREG, 29, 4, 0, 0, 0},
841{ASHA1SU0, C_ARNG, C_ARNG, C_NONE, C_ARNG, 1, 4, 0, 0, 0},
842{ASHA256H, C_ARNG, C_VREG, C_NONE, C_VREG, 1, 4, 0, 0, 0},
843{AVREV32, C_ARNG, C_NONE, C_NONE, C_ARNG, 83, 4, 0, 0, 0},
844{AVPMULL, C_ARNG, C_ARNG, C_NONE, C_ARNG, 93, 4, 0, 0, 0},
845
846{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
847{obj.APCDATA, C_VCON, C_NONE, C_NONE, C_VCON, 0, 0, 0, 0, 0},
848{obj.AFUNCDATA, C_VCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
849{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
850{obj.ANOP, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // nop variants, see #40689
851{obj.ANOP, C_REG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
852{obj.ANOP, C_VREG, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
853{obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
854{obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
855{obj.APCALIGN, C_LCON, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0}, // align code
856
857{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
858}
859
860/*
861* valid pstate field values, and value to use in instruction
862*/
863var pstatefield = []struct {
864reg int16
865enc uint32
866}{
867{REG_SPSel, 0<<16 | 4<<12 | 5<<5},
868{REG_DAIFSet, 3<<16 | 4<<12 | 6<<5},
869{REG_DAIFClr, 3<<16 | 4<<12 | 7<<5},
870}
871
872var prfopfield = []struct {
873reg int16
874enc uint32
875}{
876{REG_PLDL1KEEP, 0},
877{REG_PLDL1STRM, 1},
878{REG_PLDL2KEEP, 2},
879{REG_PLDL2STRM, 3},
880{REG_PLDL3KEEP, 4},
881{REG_PLDL3STRM, 5},
882{REG_PLIL1KEEP, 8},
883{REG_PLIL1STRM, 9},
884{REG_PLIL2KEEP, 10},
885{REG_PLIL2STRM, 11},
886{REG_PLIL3KEEP, 12},
887{REG_PLIL3STRM, 13},
888{REG_PSTL1KEEP, 16},
889{REG_PSTL1STRM, 17},
890{REG_PSTL2KEEP, 18},
891{REG_PSTL2STRM, 19},
892{REG_PSTL3KEEP, 20},
893{REG_PSTL3STRM, 21},
894}
895
896// Used for padinng NOOP instruction
897const OP_NOOP = 0xd503201f
898
899// align code to a certain length by padding bytes.
900func pcAlignPadLength(pc int64, alignedValue int64, ctxt *obj.Link) int {
901if !((alignedValue&(alignedValue-1) == 0) && 8 <= alignedValue && alignedValue <= 2048) {
902ctxt.Diag("alignment value of an instruction must be a power of two and in the range [8, 2048], got %d\n", alignedValue)
903}
904return int(-pc & (alignedValue - 1))
905}
906
907func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
908if ctxt.Retpoline {
909ctxt.Diag("-spectre=ret not supported on arm64")
910ctxt.Retpoline = false // don't keep printing
911}
912
913p := cursym.Func.Text
914if p == nil || p.Link == nil { // handle external functions and ELF section symbols
915return
916}
917
918if oprange[AAND&obj.AMask] == nil {
919ctxt.Diag("arm64 ops not initialized, call arm64.buildop first")
920}
921
922c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset & 0xffffffff), extrasize: int32(p.To.Offset >> 32)}
923p.To.Offset &= 0xffffffff // extrasize is no longer needed
924
925bflag := 1
926pc := int64(0)
927p.Pc = pc
928var m int
929var o *Optab
930for p = p.Link; p != nil; p = p.Link {
931if p.As == ADWORD && (pc&7) != 0 {
932pc += 4
933}
934p.Pc = pc
935o = c.oplook(p)
936m = int(o.size)
937if m == 0 {
938switch p.As {
939case obj.APCALIGN:
940alignedValue := p.From.Offset
941m = pcAlignPadLength(pc, alignedValue, ctxt)
942// Update the current text symbol alignment value.
943if int32(alignedValue) > cursym.Func.Align {
944cursym.Func.Align = int32(alignedValue)
945}
946break
947case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
948continue
949default:
950c.ctxt.Diag("zero-width instruction\n%v", p)
951}
952}
953switch o.flag & (LFROM | LTO) {
954case LFROM:
955c.addpool(p, &p.From)
956
957case LTO:
958c.addpool(p, &p.To)
959break
960}
961
962if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
963c.checkpool(p, 0)
964}
965pc += int64(m)
966if c.blitrl != nil {
967c.checkpool(p, 1)
968}
969}
970
971c.cursym.Size = pc
972
973/*
974* if any procedure is large enough to
975* generate a large SBRA branch, then
976* generate extra passes putting branches
977* around jmps to fix. this is rare.
978*/
979for bflag != 0 {
980bflag = 0
981pc = 0
982for p = c.cursym.Func.Text.Link; p != nil; p = p.Link {
983if p.As == ADWORD && (pc&7) != 0 {
984pc += 4
985}
986p.Pc = pc
987o = c.oplook(p)
988
989/* very large branches */
990if (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
991otxt := p.To.Target().Pc - pc
992var toofar bool
993switch o.type_ {
994case 7, 39: // branch instruction encodes 19 bits
995toofar = otxt <= -(1<<20)+10 || otxt >= (1<<20)-10
996case 40: // branch instruction encodes 14 bits
997toofar = otxt <= -(1<<15)+10 || otxt >= (1<<15)-10
998}
999if toofar {
1000q := c.newprog()
1001q.Link = p.Link
1002p.Link = q
1003q.As = AB
1004q.To.Type = obj.TYPE_BRANCH
1005q.To.SetTarget(p.To.Target())
1006p.To.SetTarget(q)
1007q = c.newprog()
1008q.Link = p.Link
1009p.Link = q
1010q.As = AB
1011q.To.Type = obj.TYPE_BRANCH
1012q.To.SetTarget(q.Link.Link)
1013bflag = 1
1014}
1015}
1016m = int(o.size)
1017
1018if m == 0 {
1019switch p.As {
1020case obj.APCALIGN:
1021alignedValue := p.From.Offset
1022m = pcAlignPadLength(pc, alignedValue, ctxt)
1023break
1024case obj.ANOP, obj.AFUNCDATA, obj.APCDATA:
1025continue
1026default:
1027c.ctxt.Diag("zero-width instruction\n%v", p)
1028}
1029}
1030
1031pc += int64(m)
1032}
1033}
1034
1035pc += -pc & (funcAlign - 1)
1036c.cursym.Size = pc
1037
1038/*
1039* lay out the code, emitting code and data relocations.
1040*/
1041c.cursym.Grow(c.cursym.Size)
1042bp := c.cursym.P
1043psz := int32(0)
1044var i int
1045var out [6]uint32
1046for p := c.cursym.Func.Text.Link; p != nil; p = p.Link {
1047c.pc = p.Pc
1048o = c.oplook(p)
1049
1050// need to align DWORDs on 8-byte boundary. The ISA doesn't
1051// require it, but the various 64-bit loads we generate assume it.
1052if o.as == ADWORD && psz%8 != 0 {
1053bp[3] = 0
1054bp[2] = bp[3]
1055bp[1] = bp[2]
1056bp[0] = bp[1]
1057bp = bp[4:]
1058psz += 4
1059}
1060
1061if int(o.size) > 4*len(out) {
1062log.Fatalf("out array in span7 is too small, need at least %d for %v", o.size/4, p)
1063}
1064if p.As == obj.APCALIGN {
1065alignedValue := p.From.Offset
1066v := pcAlignPadLength(p.Pc, alignedValue, c.ctxt)
1067for i = 0; i < int(v/4); i++ {
1068// emit ANOOP instruction by the padding size
1069c.ctxt.Arch.ByteOrder.PutUint32(bp, OP_NOOP)
1070bp = bp[4:]
1071psz += 4
1072}
1073} else {
1074c.asmout(p, o, out[:])
1075for i = 0; i < int(o.size/4); i++ {
1076c.ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
1077bp = bp[4:]
1078psz += 4
1079}
1080}
1081}
1082
1083// Mark nonpreemptible instruction sequences.
1084// We use REGTMP as a scratch register during call injection,
1085// so instruction sequences that use REGTMP are unsafe to
1086// preempt asynchronously.
1087obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint, c.isRestartable)
1088}
1089
1090// isUnsafePoint returns whether p is an unsafe point.
1091func (c *ctxt7) isUnsafePoint(p *obj.Prog) bool {
1092// If p explicitly uses REGTMP, it's unsafe to preempt, because the
1093// preemption sequence clobbers REGTMP.
1094return p.From.Reg == REGTMP || p.To.Reg == REGTMP || p.Reg == REGTMP
1095}
1096
1097// isRestartable returns whether p is a multi-instruction sequence that,
1098// if preempted, can be restarted.
1099func (c *ctxt7) isRestartable(p *obj.Prog) bool {
1100if c.isUnsafePoint(p) {
1101return false
1102}
1103// If p is a multi-instruction sequence with uses REGTMP inserted by
1104// the assembler in order to materialize a large constant/offset, we
1105// can restart p (at the start of the instruction sequence), recompute
1106// the content of REGTMP, upon async preemption. Currently, all cases
1107// of assembler-inserted REGTMP fall into this category.
1108// If p doesn't use REGTMP, it can be simply preempted, so we don't
1109// mark it.
1110o := c.oplook(p)
1111return o.size > 4 && o.flag&NOTUSETMP == 0
1112}
1113
1114/*
1115* when the first reference to the literal pool threatens
1116* to go out of range of a 1Mb PC-relative offset
1117* drop the pool now, and branch round it.
1118*/
1119func (c *ctxt7) checkpool(p *obj.Prog, skip int) {
1120if c.pool.size >= 0xffff0 || !ispcdisp(int32(p.Pc+4+int64(c.pool.size)-int64(c.pool.start)+8)) {
1121c.flushpool(p, skip)
1122} else if p.Link == nil {
1123c.flushpool(p, 2)
1124}
1125}
1126
1127func (c *ctxt7) flushpool(p *obj.Prog, skip int) {
1128if c.blitrl != nil {
1129if skip != 0 {
1130if c.ctxt.Debugvlog && skip == 1 {
1131fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), c.pool.size, c.pool.start)
1132}
1133q := c.newprog()
1134q.As = AB
1135q.To.Type = obj.TYPE_BRANCH
1136q.To.SetTarget(p.Link)
1137q.Link = c.blitrl
1138q.Pos = p.Pos
1139c.blitrl = q
1140} else if p.Pc+int64(c.pool.size)-int64(c.pool.start) < maxPCDisp {
1141return
1142}
1143
1144// The line number for constant pool entries doesn't really matter.
1145// We set it to the line number of the preceding instruction so that
1146// there are no deltas to encode in the pc-line tables.
1147for q := c.blitrl; q != nil; q = q.Link {
1148q.Pos = p.Pos
1149}
1150
1151c.elitrl.Link = p.Link
1152p.Link = c.blitrl
1153
1154c.blitrl = nil /* BUG: should refer back to values until out-of-range */
1155c.elitrl = nil
1156c.pool.size = 0
1157c.pool.start = 0
1158}
1159}
1160
1161/*
1162* MOVD foo(SB), R is actually
1163* MOVD addr, REGTMP
1164* MOVD REGTMP, R
1165* where addr is the address of the DWORD containing the address of foo.
1166*
1167* TODO: hash
1168*/
1169func (c *ctxt7) addpool(p *obj.Prog, a *obj.Addr) {
1170cls := c.aclass(a)
1171lit := c.instoffset
1172t := c.newprog()
1173t.As = AWORD
1174sz := 4
1175
1176if a.Type == obj.TYPE_CONST {
1177if lit != int64(int32(lit)) && uint64(lit) != uint64(uint32(lit)) {
1178// out of range -0x80000000 ~ 0xffffffff, must store 64-bit
1179t.As = ADWORD
1180sz = 8
1181} // else store 32-bit
1182} 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)) {
1183// conservative: don't know if we want signed or unsigned extension.
1184// in case of ambiguity, store 64-bit
1185t.As = ADWORD
1186sz = 8
1187}
1188
1189switch cls {
1190// TODO(aram): remove.
1191default:
1192if a.Name != obj.NAME_EXTERN {
1193fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(cls), p)
1194}
1195
1196t.To.Offset = a.Offset
1197t.To.Sym = a.Sym
1198t.To.Type = a.Type
1199t.To.Name = a.Name
1200
1201/* This is here because MOV uint12<<12, R is disabled in optab.
1202Because of this, we need to load the constant from memory. */
1203case C_ADDCON:
1204fallthrough
1205
1206case C_ZAUTO,
1207C_PSAUTO,
1208C_PSAUTO_8,
1209C_PSAUTO_4,
1210C_PPAUTO,
1211C_UAUTO4K_8,
1212C_UAUTO4K_4,
1213C_UAUTO4K_2,
1214C_UAUTO4K,
1215C_UAUTO8K_8,
1216C_UAUTO8K_4,
1217C_UAUTO8K,
1218C_UAUTO16K_8,
1219C_UAUTO16K,
1220C_UAUTO32K,
1221C_NSAUTO_8,
1222C_NSAUTO_4,
1223C_NSAUTO,
1224C_NPAUTO,
1225C_NAUTO4K,
1226C_LAUTO,
1227C_PPOREG,
1228C_PSOREG,
1229C_PSOREG_4,
1230C_PSOREG_8,
1231C_UOREG4K_8,
1232C_UOREG4K_4,
1233C_UOREG4K_2,
1234C_UOREG4K,
1235C_UOREG8K_8,
1236C_UOREG8K_4,
1237C_UOREG8K,
1238C_UOREG16K_8,
1239C_UOREG16K,
1240C_UOREG32K,
1241C_NSOREG_8,
1242C_NSOREG_4,
1243C_NSOREG,
1244C_NPOREG,
1245C_NOREG4K,
1246C_LOREG,
1247C_LACON,
1248C_ADDCON2,
1249C_LCON,
1250C_VCON:
1251if a.Name == obj.NAME_EXTERN {
1252fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(cls), p)
1253}
1254
1255t.To.Type = obj.TYPE_CONST
1256t.To.Offset = lit
1257break
1258}
1259
1260for q := c.blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
1261if q.To == t.To {
1262p.Pool = q
1263return
1264}
1265}
1266
1267q := c.newprog()
1268*q = *t
1269q.Pc = int64(c.pool.size)
1270if c.blitrl == nil {
1271c.blitrl = q
1272c.pool.start = uint32(p.Pc)
1273} else {
1274c.elitrl.Link = q
1275}
1276c.elitrl = q
1277c.pool.size = -c.pool.size & (funcAlign - 1)
1278c.pool.size += uint32(sz)
1279p.Pool = q
1280}
1281
1282func (c *ctxt7) regoff(a *obj.Addr) uint32 {
1283c.instoffset = 0
1284c.aclass(a)
1285return uint32(c.instoffset)
1286}
1287
1288func isSTLXRop(op obj.As) bool {
1289switch op {
1290case ASTLXR, ASTLXRW, ASTLXRB, ASTLXRH,
1291ASTXR, ASTXRW, ASTXRB, ASTXRH:
1292return true
1293}
1294return false
1295}
1296
1297func isSTXPop(op obj.As) bool {
1298switch op {
1299case ASTXP, ASTLXP, ASTXPW, ASTLXPW:
1300return true
1301}
1302return false
1303}
1304
1305func isANDop(op obj.As) bool {
1306switch op {
1307case AAND, AORR, AEOR, AANDS, ATST,
1308ABIC, AEON, AORN, ABICS:
1309return true
1310}
1311return false
1312}
1313
1314func isANDWop(op obj.As) bool {
1315switch op {
1316case AANDW, AORRW, AEORW, AANDSW, ATSTW,
1317ABICW, AEONW, AORNW, ABICSW:
1318return true
1319}
1320return false
1321}
1322
1323func isADDop(op obj.As) bool {
1324switch op {
1325case AADD, AADDS, ASUB, ASUBS, ACMN, ACMP:
1326return true
1327}
1328return false
1329}
1330
1331func isADDWop(op obj.As) bool {
1332switch op {
1333case AADDW, AADDSW, ASUBW, ASUBSW, ACMNW, ACMPW:
1334return true
1335}
1336return false
1337}
1338
1339func isRegShiftOrExt(a *obj.Addr) bool {
1340return (a.Index-obj.RBaseARM64)®_EXT != 0 || (a.Index-obj.RBaseARM64)®_LSL != 0
1341}
1342
1343// Maximum PC-relative displacement.
1344// The actual limit is ±2²⁰, but we are conservative
1345// to avoid needing to recompute the literal pool flush points
1346// as span-dependent jumps are enlarged.
1347const maxPCDisp = 512 * 1024
1348
1349// ispcdisp reports whether v is a valid PC-relative displacement.
1350func ispcdisp(v int32) bool {
1351return -maxPCDisp < v && v < maxPCDisp && v&3 == 0
1352}
1353
1354func isaddcon(v int64) bool {
1355/* uimm12 or uimm24? */
1356if v < 0 {
1357return false
1358}
1359if (v & 0xFFF) == 0 {
1360v >>= 12
1361}
1362return v <= 0xFFF
1363}
1364
1365func isaddcon2(v int64) bool {
1366return 0 <= v && v <= 0xFFFFFF
1367}
1368
1369// isbitcon reports whether a constant can be encoded into a logical instruction.
1370// bitcon has a binary form of repetition of a bit sequence of length 2, 4, 8, 16, 32, or 64,
1371// which itself is a rotate (w.r.t. the length of the unit) of a sequence of ones.
1372// special cases: 0 and -1 are not bitcon.
1373// this function needs to run against virtually all the constants, so it needs to be fast.
1374// for this reason, bitcon testing and bitcon encoding are separate functions.
1375func isbitcon(x uint64) bool {
1376if x == 1<<64-1 || x == 0 {
1377return false
1378}
1379// determine the period and sign-extend a unit to 64 bits
1380switch {
1381case x != x>>32|x<<32:
1382// period is 64
1383// nothing to do
1384case x != x>>16|x<<48:
1385// period is 32
1386x = uint64(int64(int32(x)))
1387case x != x>>8|x<<56:
1388// period is 16
1389x = uint64(int64(int16(x)))
1390case x != x>>4|x<<60:
1391// period is 8
1392x = uint64(int64(int8(x)))
1393default:
1394// period is 4 or 2, always true
1395// 0001, 0010, 0100, 1000 -- 0001 rotate
1396// 0011, 0110, 1100, 1001 -- 0011 rotate
1397// 0111, 1011, 1101, 1110 -- 0111 rotate
1398// 0101, 1010 -- 01 rotate, repeat
1399return true
1400}
1401return sequenceOfOnes(x) || sequenceOfOnes(^x)
1402}
1403
1404// sequenceOfOnes tests whether a constant is a sequence of ones in binary, with leading and trailing zeros
1405func sequenceOfOnes(x uint64) bool {
1406y := x & -x // lowest set bit of x. x is good iff x+y is a power of 2
1407y += x
1408return (y-1)&y == 0
1409}
1410
1411// bitconEncode returns the encoding of a bitcon used in logical instructions
1412// x is known to be a bitcon
1413// a bitcon is a sequence of n ones at low bits (i.e. 1<<n-1), right rotated
1414// by R bits, and repeated with period of 64, 32, 16, 8, 4, or 2.
1415// it is encoded in logical instructions with 3 bitfields
1416// N (1 bit) : R (6 bits) : S (6 bits), where
1417// N=1 -- period=64
1418// N=0, S=0xxxxx -- period=32
1419// N=0, S=10xxxx -- period=16
1420// N=0, S=110xxx -- period=8
1421// N=0, S=1110xx -- period=4
1422// N=0, S=11110x -- period=2
1423// R is the shift amount, low bits of S = n-1
1424func bitconEncode(x uint64, mode int) uint32 {
1425var period uint32
1426// determine the period and sign-extend a unit to 64 bits
1427switch {
1428case x != x>>32|x<<32:
1429period = 64
1430case x != x>>16|x<<48:
1431period = 32
1432x = uint64(int64(int32(x)))
1433case x != x>>8|x<<56:
1434period = 16
1435x = uint64(int64(int16(x)))
1436case x != x>>4|x<<60:
1437period = 8
1438x = uint64(int64(int8(x)))
1439case x != x>>2|x<<62:
1440period = 4
1441x = uint64(int64(x<<60) >> 60)
1442default:
1443period = 2
1444x = uint64(int64(x<<62) >> 62)
1445}
1446neg := false
1447if int64(x) < 0 {
1448x = ^x
1449neg = true
1450}
1451y := x & -x // lowest set bit of x.
1452s := log2(y)
1453n := log2(x+y) - s // x (or ^x) is a sequence of n ones left shifted by s bits
1454if neg {
1455// ^x is a sequence of n ones left shifted by s bits
1456// adjust n, s for x
1457s = n + s
1458n = period - n
1459}
1460
1461N := uint32(0)
1462if mode == 64 && period == 64 {
1463N = 1
1464}
1465R := (period - s) & (period - 1) & uint32(mode-1) // shift amount of right rotate
1466S := (n - 1) | 63&^(period<<1-1) // low bits = #ones - 1, high bits encodes period
1467return N<<22 | R<<16 | S<<10
1468}
1469
1470func log2(x uint64) uint32 {
1471if x == 0 {
1472panic("log2 of 0")
1473}
1474n := uint32(0)
1475if x >= 1<<32 {
1476x >>= 32
1477n += 32
1478}
1479if x >= 1<<16 {
1480x >>= 16
1481n += 16
1482}
1483if x >= 1<<8 {
1484x >>= 8
1485n += 8
1486}
1487if x >= 1<<4 {
1488x >>= 4
1489n += 4
1490}
1491if x >= 1<<2 {
1492x >>= 2
1493n += 2
1494}
1495if x >= 1<<1 {
1496x >>= 1
1497n += 1
1498}
1499return n
1500}
1501
1502func autoclass(l int64) int {
1503if l == 0 {
1504return C_ZAUTO
1505}
1506
1507if l < 0 {
1508if l >= -256 && (l&7) == 0 {
1509return C_NSAUTO_8
1510}
1511if l >= -256 && (l&3) == 0 {
1512return C_NSAUTO_4
1513}
1514if l >= -256 {
1515return C_NSAUTO
1516}
1517if l >= -512 && (l&7) == 0 {
1518return C_NPAUTO
1519}
1520if l >= -4095 {
1521return C_NAUTO4K
1522}
1523return C_LAUTO
1524}
1525
1526if l <= 255 {
1527if (l & 7) == 0 {
1528return C_PSAUTO_8
1529}
1530if (l & 3) == 0 {
1531return C_PSAUTO_4
1532}
1533return C_PSAUTO
1534}
1535if l <= 504 && l&7 == 0 {
1536return C_PPAUTO
1537}
1538if l <= 4095 {
1539if l&7 == 0 {
1540return C_UAUTO4K_8
1541}
1542if l&3 == 0 {
1543return C_UAUTO4K_4
1544}
1545if l&1 == 0 {
1546return C_UAUTO4K_2
1547}
1548return C_UAUTO4K
1549}
1550if l <= 8190 {
1551if l&7 == 0 {
1552return C_UAUTO8K_8
1553}
1554if l&3 == 0 {
1555return C_UAUTO8K_4
1556}
1557if l&1 == 0 {
1558return C_UAUTO8K
1559}
1560}
1561if l <= 16380 {
1562if l&7 == 0 {
1563return C_UAUTO16K_8
1564}
1565if l&3 == 0 {
1566return C_UAUTO16K
1567}
1568}
1569if l <= 32760 && (l&7) == 0 {
1570return C_UAUTO32K
1571}
1572return C_LAUTO
1573}
1574
1575func oregclass(l int64) int {
1576return autoclass(l) - C_ZAUTO + C_ZOREG
1577}
1578
1579/*
1580* given an offset v and a class c (see above)
1581* return the offset value to use in the instruction,
1582* scaled if necessary
1583*/
1584func (c *ctxt7) offsetshift(p *obj.Prog, v int64, cls int) int64 {
1585s := 0
1586if cls >= C_SEXT1 && cls <= C_SEXT16 {
1587s = cls - C_SEXT1
1588} else {
1589switch cls {
1590case C_UAUTO4K, C_UOREG4K, C_ZOREG:
1591s = 0
1592case C_UAUTO8K, C_UOREG8K:
1593s = 1
1594case C_UAUTO16K, C_UOREG16K:
1595s = 2
1596case C_UAUTO32K, C_UOREG32K:
1597s = 3
1598default:
1599c.ctxt.Diag("bad class: %v\n%v", DRconv(cls), p)
1600}
1601}
1602vs := v >> uint(s)
1603if vs<<uint(s) != v {
1604c.ctxt.Diag("odd offset: %d\n%v", v, p)
1605}
1606return vs
1607}
1608
1609/*
1610* if v contains a single 16-bit value aligned
1611* on a 16-bit field, and thus suitable for movk/movn,
1612* return the field index 0 to 3; otherwise return -1
1613*/
1614func movcon(v int64) int {
1615for s := 0; s < 64; s += 16 {
1616if (uint64(v) &^ (uint64(0xFFFF) << uint(s))) == 0 {
1617return s / 16
1618}
1619}
1620return -1
1621}
1622
1623func rclass(r int16) int {
1624switch {
1625case REG_R0 <= r && r <= REG_R30: // not 31
1626return C_REG
1627case r == REGZERO:
1628return C_ZCON
1629case REG_F0 <= r && r <= REG_F31:
1630return C_FREG
1631case REG_V0 <= r && r <= REG_V31:
1632return C_VREG
1633case COND_EQ <= r && r <= COND_NV:
1634return C_COND
1635case r == REGSP:
1636return C_RSP
1637case r >= REG_ARNG && r < REG_ELEM:
1638return C_ARNG
1639case r >= REG_ELEM && r < REG_ELEM_END:
1640return C_ELEM
1641case r >= REG_UXTB && r < REG_SPECIAL:
1642return C_EXTREG
1643case r >= REG_SPECIAL:
1644return C_SPR
1645}
1646return C_GOK
1647}
1648
1649// con32class reclassifies the constant of 32-bit instruction. Because the constant type is 32-bit,
1650// but saved in Offset which type is int64, con32class treats it as uint32 type and reclassifies it.
1651func (c *ctxt7) con32class(a *obj.Addr) int {
1652v := uint32(a.Offset)
1653if v == 0 {
1654return C_ZCON
1655}
1656if isaddcon(int64(v)) {
1657if v <= 0xFFF {
1658if isbitcon(uint64(a.Offset)) {
1659return C_ABCON0
1660}
1661return C_ADDCON0
1662}
1663if isbitcon(uint64(a.Offset)) {
1664return C_ABCON
1665}
1666if movcon(int64(v)) >= 0 {
1667return C_AMCON
1668}
1669if movcon(int64(^v)) >= 0 {
1670return C_AMCON
1671}
1672return C_ADDCON
1673}
1674
1675t := movcon(int64(v))
1676if t >= 0 {
1677if isbitcon(uint64(a.Offset)) {
1678return C_MBCON
1679}
1680return C_MOVCON
1681}
1682
1683t = movcon(int64(^v))
1684if t >= 0 {
1685if isbitcon(uint64(a.Offset)) {
1686return C_MBCON
1687}
1688return C_MOVCON
1689}
1690
1691if isbitcon(uint64(a.Offset)) {
1692return C_BITCON
1693}
1694
1695if 0 <= v && v <= 0xffffff {
1696return C_ADDCON2
1697}
1698return C_LCON
1699}
1700
1701// con64class reclassifies the constant of C_VCON and C_LCON class.
1702func (c *ctxt7) con64class(a *obj.Addr) int {
1703zeroCount := 0
1704negCount := 0
1705for i := uint(0); i < 4; i++ {
1706immh := uint32(a.Offset >> (i * 16) & 0xffff)
1707if immh == 0 {
1708zeroCount++
1709} else if immh == 0xffff {
1710negCount++
1711}
1712}
1713if zeroCount >= 3 || negCount >= 3 {
1714return C_MOVCON
1715} else if zeroCount == 2 || negCount == 2 {
1716return C_MOVCON2
1717} else if zeroCount == 1 || negCount == 1 {
1718return C_MOVCON3
1719} else {
1720return C_VCON
1721}
1722}
1723
1724func (c *ctxt7) aclass(a *obj.Addr) int {
1725switch a.Type {
1726case obj.TYPE_NONE:
1727return C_NONE
1728
1729case obj.TYPE_REG:
1730return rclass(a.Reg)
1731
1732case obj.TYPE_REGREG:
1733return C_PAIR
1734
1735case obj.TYPE_SHIFT:
1736return C_SHIFT
1737
1738case obj.TYPE_REGLIST:
1739return C_LIST
1740
1741case obj.TYPE_MEM:
1742// The base register should be an integer register.
1743if int16(REG_F0) <= a.Reg && a.Reg <= int16(REG_V31) {
1744break
1745}
1746switch a.Name {
1747case obj.NAME_EXTERN, obj.NAME_STATIC:
1748if a.Sym == nil {
1749break
1750}
1751c.instoffset = a.Offset
1752if a.Sym != nil { // use relocation
1753if a.Sym.Type == objabi.STLSBSS {
1754if c.ctxt.Flag_shared {
1755return C_TLS_IE
1756} else {
1757return C_TLS_LE
1758}
1759}
1760return C_ADDR
1761}
1762return C_LEXT
1763
1764case obj.NAME_GOTREF:
1765return C_GOTADDR
1766
1767case obj.NAME_AUTO:
1768if a.Reg == REGSP {
1769// unset base register for better printing, since
1770// a.Offset is still relative to pseudo-SP.
1771a.Reg = obj.REG_NONE
1772}
1773// The frame top 8 or 16 bytes are for FP
1774c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize)
1775return autoclass(c.instoffset)
1776
1777case obj.NAME_PARAM:
1778if a.Reg == REGSP {
1779// unset base register for better printing, since
1780// a.Offset is still relative to pseudo-FP.
1781a.Reg = obj.REG_NONE
1782}
1783c.instoffset = int64(c.autosize) + a.Offset + 8
1784return autoclass(c.instoffset)
1785
1786case obj.NAME_NONE:
1787if a.Index != 0 {
1788if a.Offset != 0 {
1789if isRegShiftOrExt(a) {
1790// extended or shifted register offset, (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2).
1791return C_ROFF
1792}
1793return C_GOK
1794}
1795// register offset, (Rn)(Rm)
1796return C_ROFF
1797}
1798c.instoffset = a.Offset
1799return oregclass(c.instoffset)
1800}
1801return C_GOK
1802
1803case obj.TYPE_FCONST:
1804return C_FCON
1805
1806case obj.TYPE_TEXTSIZE:
1807return C_TEXTSIZE
1808
1809case obj.TYPE_CONST, obj.TYPE_ADDR:
1810switch a.Name {
1811case obj.NAME_NONE:
1812c.instoffset = a.Offset
1813if a.Reg != 0 && a.Reg != REGZERO {
1814break
1815}
1816v := c.instoffset
1817if v == 0 {
1818return C_ZCON
1819}
1820if isaddcon(v) {
1821if v <= 0xFFF {
1822if isbitcon(uint64(v)) {
1823return C_ABCON0
1824}
1825return C_ADDCON0
1826}
1827if isbitcon(uint64(v)) {
1828return C_ABCON
1829}
1830if movcon(v) >= 0 {
1831return C_AMCON
1832}
1833if movcon(^v) >= 0 {
1834return C_AMCON
1835}
1836return C_ADDCON
1837}
1838
1839t := movcon(v)
1840if t >= 0 {
1841if isbitcon(uint64(v)) {
1842return C_MBCON
1843}
1844return C_MOVCON
1845}
1846
1847t = movcon(^v)
1848if t >= 0 {
1849if isbitcon(uint64(v)) {
1850return C_MBCON
1851}
1852return C_MOVCON
1853}
1854
1855if isbitcon(uint64(v)) {
1856return C_BITCON
1857}
1858
1859if 0 <= v && v <= 0xffffff {
1860return C_ADDCON2
1861}
1862
1863if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) {
1864return C_LCON
1865}
1866return C_VCON
1867
1868case obj.NAME_EXTERN, obj.NAME_STATIC:
1869if a.Sym == nil {
1870return C_GOK
1871}
1872if a.Sym.Type == objabi.STLSBSS {
1873c.ctxt.Diag("taking address of TLS variable is not supported")
1874}
1875c.instoffset = a.Offset
1876return C_VCONADDR
1877
1878case obj.NAME_AUTO:
1879if a.Reg == REGSP {
1880// unset base register for better printing, since
1881// a.Offset is still relative to pseudo-SP.
1882a.Reg = obj.REG_NONE
1883}
1884// The frame top 8 or 16 bytes are for FP
1885c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize)
1886
1887case obj.NAME_PARAM:
1888if a.Reg == REGSP {
1889// unset base register for better printing, since
1890// a.Offset is still relative to pseudo-FP.
1891a.Reg = obj.REG_NONE
1892}
1893c.instoffset = int64(c.autosize) + a.Offset + 8
1894default:
1895return C_GOK
1896}
1897cf := c.instoffset
1898if isaddcon(cf) || isaddcon(-cf) {
1899return C_AACON
1900}
1901if isaddcon2(cf) {
1902return C_AACON2
1903}
1904
1905return C_LACON
1906
1907case obj.TYPE_BRANCH:
1908return C_SBRA
1909}
1910
1911return C_GOK
1912}
1913
1914func oclass(a *obj.Addr) int {
1915return int(a.Class) - 1
1916}
1917
1918func (c *ctxt7) oplook(p *obj.Prog) *Optab {
1919a1 := int(p.Optab)
1920if a1 != 0 {
1921return &optab[a1-1]
1922}
1923a1 = int(p.From.Class)
1924if a1 == 0 {
1925a0 := c.aclass(&p.From)
1926// do not break C_ADDCON2 when S bit is set
1927if (p.As == AADDS || p.As == AADDSW || p.As == ASUBS || p.As == ASUBSW) && a0 == C_ADDCON2 {
1928a0 = C_LCON
1929}
1930a1 = a0 + 1
1931p.From.Class = int8(a1)
1932// more specific classification of 32-bit integers
1933if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE {
1934if p.As == AMOVW || isADDWop(p.As) {
1935ra0 := c.con32class(&p.From)
1936// do not break C_ADDCON2 when S bit is set
1937if (p.As == AADDSW || p.As == ASUBSW) && ra0 == C_ADDCON2 {
1938ra0 = C_LCON
1939}
1940a1 = ra0 + 1
1941p.From.Class = int8(a1)
1942}
1943if isANDWop(p.As) && a0 != C_BITCON {
1944// For 32-bit logical instruction with constant,
1945// the BITCON test is special in that it looks at
1946// the 64-bit which has the high 32-bit as a copy
1947// of the low 32-bit. We have handled that and
1948// don't pass it to con32class.
1949a1 = c.con32class(&p.From) + 1
1950p.From.Class = int8(a1)
1951}
1952if ((p.As == AMOVD) || isANDop(p.As) || isADDop(p.As)) && (a0 == C_LCON || a0 == C_VCON) {
1953a1 = c.con64class(&p.From) + 1
1954p.From.Class = int8(a1)
1955}
1956}
1957}
1958
1959a1--
1960a3 := C_NONE + 1
1961if p.GetFrom3() != nil {
1962a3 = int(p.GetFrom3().Class)
1963if a3 == 0 {
1964a3 = c.aclass(p.GetFrom3()) + 1
1965p.GetFrom3().Class = int8(a3)
1966}
1967}
1968
1969a3--
1970a4 := int(p.To.Class)
1971if a4 == 0 {
1972a4 = c.aclass(&p.To) + 1
1973p.To.Class = int8(a4)
1974}
1975
1976a4--
1977a2 := C_NONE
1978if p.Reg != 0 {
1979a2 = rclass(p.Reg)
1980}
1981
1982if false {
1983fmt.Printf("oplook %v %d %d %d %d\n", p.As, a1, a2, a3, a4)
1984fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
1985}
1986
1987ops := oprange[p.As&obj.AMask]
1988c1 := &xcmp[a1]
1989c2 := &xcmp[a2]
1990c3 := &xcmp[a3]
1991c4 := &xcmp[a4]
1992c5 := &xcmp[p.Scond>>5]
1993for i := range ops {
1994op := &ops[i]
1995if (int(op.a2) == a2 || c2[op.a2]) && c5[op.scond>>5] && c1[op.a1] && c3[op.a3] && c4[op.a4] {
1996p.Optab = uint16(cap(optab) - cap(ops) + i + 1)
1997return op
1998}
1999}
2000
2001c.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)
2002// Turn illegal instruction into an UNDEF, avoid crashing in asmout
2003return &Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0}
2004}
2005
2006func cmp(a int, b int) bool {
2007if a == b {
2008return true
2009}
2010switch a {
2011case C_RSP:
2012if b == C_REG {
2013return true
2014}
2015
2016case C_REG:
2017if b == C_ZCON {
2018return true
2019}
2020
2021case C_ADDCON0:
2022if b == C_ZCON || b == C_ABCON0 {
2023return true
2024}
2025
2026case C_ADDCON:
2027if b == C_ZCON || b == C_ABCON0 || b == C_ADDCON0 || b == C_ABCON || b == C_AMCON {
2028return true
2029}
2030
2031case C_BITCON:
2032if b == C_ABCON0 || b == C_ABCON || b == C_MBCON {
2033return true
2034}
2035
2036case C_MOVCON:
2037if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 || b == C_AMCON {
2038return true
2039}
2040
2041case C_ADDCON2:
2042if b == C_ZCON || b == C_ADDCON || b == C_ADDCON0 {
2043return true
2044}
2045
2046case C_LCON:
2047if 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 {
2048return true
2049}
2050
2051case C_MOVCON2:
2052return cmp(C_LCON, b)
2053
2054case C_VCON:
2055return cmp(C_LCON, b)
2056
2057case C_LACON:
2058if b == C_AACON || b == C_AACON2 {
2059return true
2060}
2061
2062case C_SEXT2:
2063if b == C_SEXT1 {
2064return true
2065}
2066
2067case C_SEXT4:
2068if b == C_SEXT1 || b == C_SEXT2 {
2069return true
2070}
2071
2072case C_SEXT8:
2073if b >= C_SEXT1 && b <= C_SEXT4 {
2074return true
2075}
2076
2077case C_SEXT16:
2078if b >= C_SEXT1 && b <= C_SEXT8 {
2079return true
2080}
2081
2082case C_LEXT:
2083if b >= C_SEXT1 && b <= C_SEXT16 {
2084return true
2085}
2086
2087case C_NSAUTO_4:
2088if b == C_NSAUTO_8 {
2089return true
2090}
2091
2092case C_NSAUTO:
2093switch b {
2094case C_NSAUTO_4, C_NSAUTO_8:
2095return true
2096}
2097
2098case C_NPAUTO:
2099switch b {
2100case C_NSAUTO_8:
2101return true
2102}
2103
2104case C_NAUTO4K:
2105switch b {
2106case C_NSAUTO_8, C_NSAUTO_4, C_NSAUTO, C_NPAUTO:
2107return true
2108}
2109
2110case C_PSAUTO_8:
2111if b == C_ZAUTO {
2112return true
2113}
2114
2115case C_PSAUTO_4:
2116switch b {
2117case C_ZAUTO, C_PSAUTO_8:
2118return true
2119}
2120
2121case C_PSAUTO:
2122switch b {
2123case C_ZAUTO, C_PSAUTO_8, C_PSAUTO_4:
2124return true
2125}
2126
2127case C_PPAUTO:
2128switch b {
2129case C_ZAUTO, C_PSAUTO_8:
2130return true
2131}
2132
2133case C_UAUTO4K:
2134switch b {
2135case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
2136C_PPAUTO, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8:
2137return true
2138}
2139
2140case C_UAUTO8K:
2141switch b {
2142case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
2143C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8:
2144return true
2145}
2146
2147case C_UAUTO16K:
2148switch b {
2149case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
2150C_UAUTO4K_4, C_UAUTO4K_8, C_UAUTO8K_4, C_UAUTO8K_8, C_UAUTO16K_8:
2151return true
2152}
2153
2154case C_UAUTO32K:
2155switch b {
2156case C_ZAUTO, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8,
2157C_PPAUTO, C_UAUTO4K_8, C_UAUTO8K_8, C_UAUTO16K_8:
2158return true
2159}
2160
2161case C_LAUTO:
2162switch b {
2163case C_ZAUTO, C_NSAUTO, C_NSAUTO_4, C_NSAUTO_8, C_NPAUTO,
2164C_NAUTO4K, C_PSAUTO, C_PSAUTO_4, C_PSAUTO_8, C_PPAUTO,
2165C_UAUTO4K, C_UAUTO4K_2, C_UAUTO4K_4, C_UAUTO4K_8,
2166C_UAUTO8K, C_UAUTO8K_4, C_UAUTO8K_8,
2167C_UAUTO16K, C_UAUTO16K_8,
2168C_UAUTO32K:
2169return true
2170}
2171
2172case C_NSOREG_4:
2173if b == C_NSOREG_8 {
2174return true
2175}
2176
2177case C_NSOREG:
2178switch b {
2179case C_NSOREG_4, C_NSOREG_8:
2180return true
2181}
2182
2183case C_NPOREG:
2184switch b {
2185case C_NSOREG_8:
2186return true
2187}
2188
2189case C_NOREG4K:
2190switch b {
2191case C_NSOREG_8, C_NSOREG_4, C_NSOREG, C_NPOREG:
2192return true
2193}
2194
2195case C_PSOREG_4:
2196switch b {
2197case C_ZOREG, C_PSOREG_8:
2198return true
2199}
2200
2201case C_PSOREG:
2202switch b {
2203case C_ZOREG, C_PSOREG_8, C_PSOREG_4:
2204return true
2205}
2206
2207case C_PPOREG:
2208switch b {
2209case C_ZOREG, C_PSOREG_8:
2210return true
2211}
2212
2213case C_UOREG4K:
2214switch b {
2215case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
2216C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8:
2217return true
2218}
2219
2220case C_UOREG8K:
2221switch b {
2222case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
2223C_PPOREG, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
2224C_UOREG8K_4, C_UOREG8K_8:
2225return true
2226}
2227
2228case C_UOREG16K:
2229switch b {
2230case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
2231C_PPOREG, C_UOREG4K_4, C_UOREG4K_8, C_UOREG8K_4,
2232C_UOREG8K_8, C_UOREG16K_8:
2233return true
2234}
2235
2236case C_UOREG32K:
2237switch b {
2238case C_ZOREG, C_PSOREG_4, C_PSOREG_8, C_PSOREG,
2239C_PPOREG, C_UOREG4K_8, C_UOREG8K_8, C_UOREG16K_8:
2240return true
2241}
2242
2243case C_LOREG:
2244switch b {
2245case C_ZOREG, C_NSOREG, C_NSOREG_4, C_NSOREG_8, C_NPOREG,
2246C_NOREG4K, C_PSOREG_4, C_PSOREG_8, C_PSOREG, C_PPOREG,
2247C_UOREG4K, C_UOREG4K_2, C_UOREG4K_4, C_UOREG4K_8,
2248C_UOREG8K, C_UOREG8K_4, C_UOREG8K_8,
2249C_UOREG16K, C_UOREG16K_8,
2250C_UOREG32K:
2251return true
2252}
2253
2254case C_LBRA:
2255if b == C_SBRA {
2256return true
2257}
2258}
2259
2260return false
2261}
2262
2263type ocmp []Optab
2264
2265func (x ocmp) Len() int {
2266return len(x)
2267}
2268
2269func (x ocmp) Swap(i, j int) {
2270x[i], x[j] = x[j], x[i]
2271}
2272
2273func (x ocmp) Less(i, j int) bool {
2274p1 := &x[i]
2275p2 := &x[j]
2276if p1.as != p2.as {
2277return p1.as < p2.as
2278}
2279if p1.a1 != p2.a1 {
2280return p1.a1 < p2.a1
2281}
2282if p1.a2 != p2.a2 {
2283return p1.a2 < p2.a2
2284}
2285if p1.a3 != p2.a3 {
2286return p1.a3 < p2.a3
2287}
2288if p1.a4 != p2.a4 {
2289return p1.a4 < p2.a4
2290}
2291if p1.scond != p2.scond {
2292return p1.scond < p2.scond
2293}
2294return false
2295}
2296
2297func oprangeset(a obj.As, t []Optab) {
2298oprange[a&obj.AMask] = t
2299}
2300
2301func buildop(ctxt *obj.Link) {
2302if oprange[AAND&obj.AMask] != nil {
2303// Already initialized; stop now.
2304// This happens in the cmd/asm tests,
2305// each of which re-initializes the arch.
2306return
2307}
2308
2309var n int
2310for i := 0; i < C_GOK; i++ {
2311for n = 0; n < C_GOK; n++ {
2312if cmp(n, i) {
2313xcmp[i][n] = true
2314}
2315}
2316}
2317for n = 0; optab[n].as != obj.AXXX; n++ {
2318}
2319sort.Sort(ocmp(optab[:n]))
2320for i := 0; i < n; i++ {
2321r := optab[i].as
2322start := i
2323for optab[i].as == r {
2324i++
2325}
2326t := optab[start:i]
2327i--
2328oprangeset(r, t)
2329switch r {
2330default:
2331ctxt.Diag("unknown op in build: %v", r)
2332ctxt.DiagFlush()
2333log.Fatalf("bad code")
2334
2335case AADD:
2336oprangeset(AADDS, t)
2337oprangeset(ASUB, t)
2338oprangeset(ASUBS, t)
2339oprangeset(AADDW, t)
2340oprangeset(AADDSW, t)
2341oprangeset(ASUBW, t)
2342oprangeset(ASUBSW, t)
2343
2344case AAND: /* logical immediate, logical shifted register */
2345oprangeset(AANDW, t)
2346oprangeset(AEOR, t)
2347oprangeset(AEORW, t)
2348oprangeset(AORR, t)
2349oprangeset(AORRW, t)
2350oprangeset(ABIC, t)
2351oprangeset(ABICW, t)
2352oprangeset(AEON, t)
2353oprangeset(AEONW, t)
2354oprangeset(AORN, t)
2355oprangeset(AORNW, t)
2356
2357case AANDS: /* logical immediate, logical shifted register, set flags, cannot target RSP */
2358oprangeset(AANDSW, t)
2359oprangeset(ABICS, t)
2360oprangeset(ABICSW, t)
2361
2362case ANEG:
2363oprangeset(ANEGS, t)
2364oprangeset(ANEGSW, t)
2365oprangeset(ANEGW, t)
2366
2367case AADC: /* rn=Rd */
2368oprangeset(AADCW, t)
2369
2370oprangeset(AADCS, t)
2371oprangeset(AADCSW, t)
2372oprangeset(ASBC, t)
2373oprangeset(ASBCW, t)
2374oprangeset(ASBCS, t)
2375oprangeset(ASBCSW, t)
2376
2377case ANGC: /* rn=REGZERO */
2378oprangeset(ANGCW, t)
2379
2380oprangeset(ANGCS, t)
2381oprangeset(ANGCSW, t)
2382
2383case ACMP:
2384oprangeset(ACMPW, t)
2385oprangeset(ACMN, t)
2386oprangeset(ACMNW, t)
2387
2388case ATST:
2389oprangeset(ATSTW, t)
2390
2391/* register/register, and shifted */
2392case AMVN:
2393oprangeset(AMVNW, t)
2394
2395case AMOVK:
2396oprangeset(AMOVKW, t)
2397oprangeset(AMOVN, t)
2398oprangeset(AMOVNW, t)
2399oprangeset(AMOVZ, t)
2400oprangeset(AMOVZW, t)
2401
2402case ASWPD:
2403for i := range atomicInstructions {
2404oprangeset(i, t)
2405}
2406
2407case ABEQ:
2408oprangeset(ABNE, t)
2409oprangeset(ABCS, t)
2410oprangeset(ABHS, t)
2411oprangeset(ABCC, t)
2412oprangeset(ABLO, t)
2413oprangeset(ABMI, t)
2414oprangeset(ABPL, t)
2415oprangeset(ABVS, t)
2416oprangeset(ABVC, t)
2417oprangeset(ABHI, t)
2418oprangeset(ABLS, t)
2419oprangeset(ABGE, t)
2420oprangeset(ABLT, t)
2421oprangeset(ABGT, t)
2422oprangeset(ABLE, t)
2423
2424case ALSL:
2425oprangeset(ALSLW, t)
2426oprangeset(ALSR, t)
2427oprangeset(ALSRW, t)
2428oprangeset(AASR, t)
2429oprangeset(AASRW, t)
2430oprangeset(AROR, t)
2431oprangeset(ARORW, t)
2432
2433case ACLS:
2434oprangeset(ACLSW, t)
2435oprangeset(ACLZ, t)
2436oprangeset(ACLZW, t)
2437oprangeset(ARBIT, t)
2438oprangeset(ARBITW, t)
2439oprangeset(AREV, t)
2440oprangeset(AREVW, t)
2441oprangeset(AREV16, t)
2442oprangeset(AREV16W, t)
2443oprangeset(AREV32, t)
2444
2445case ASDIV:
2446oprangeset(ASDIVW, t)
2447oprangeset(AUDIV, t)
2448oprangeset(AUDIVW, t)
2449oprangeset(ACRC32B, t)
2450oprangeset(ACRC32CB, t)
2451oprangeset(ACRC32CH, t)
2452oprangeset(ACRC32CW, t)
2453oprangeset(ACRC32CX, t)
2454oprangeset(ACRC32H, t)
2455oprangeset(ACRC32W, t)
2456oprangeset(ACRC32X, t)
2457
2458case AMADD:
2459oprangeset(AMADDW, t)
2460oprangeset(AMSUB, t)
2461oprangeset(AMSUBW, t)
2462oprangeset(ASMADDL, t)
2463oprangeset(ASMSUBL, t)
2464oprangeset(AUMADDL, t)
2465oprangeset(AUMSUBL, t)
2466
2467case AREM:
2468oprangeset(AREMW, t)
2469oprangeset(AUREM, t)
2470oprangeset(AUREMW, t)
2471
2472case AMUL:
2473oprangeset(AMULW, t)
2474oprangeset(AMNEG, t)
2475oprangeset(AMNEGW, t)
2476oprangeset(ASMNEGL, t)
2477oprangeset(ASMULL, t)
2478oprangeset(ASMULH, t)
2479oprangeset(AUMNEGL, t)
2480oprangeset(AUMULH, t)
2481oprangeset(AUMULL, t)
2482
2483case AMOVB:
2484oprangeset(AMOVBU, t)
2485
2486case AMOVH:
2487oprangeset(AMOVHU, t)
2488
2489case AMOVW:
2490oprangeset(AMOVWU, t)
2491
2492case ABFM:
2493oprangeset(ABFMW, t)
2494oprangeset(ASBFM, t)
2495oprangeset(ASBFMW, t)
2496oprangeset(AUBFM, t)
2497oprangeset(AUBFMW, t)
2498
2499case ABFI:
2500oprangeset(ABFIW, t)
2501oprangeset(ABFXIL, t)
2502oprangeset(ABFXILW, t)
2503oprangeset(ASBFIZ, t)
2504oprangeset(ASBFIZW, t)
2505oprangeset(ASBFX, t)
2506oprangeset(ASBFXW, t)
2507oprangeset(AUBFIZ, t)
2508oprangeset(AUBFIZW, t)
2509oprangeset(AUBFX, t)
2510oprangeset(AUBFXW, t)
2511
2512case AEXTR:
2513oprangeset(AEXTRW, t)
2514
2515case ASXTB:
2516oprangeset(ASXTBW, t)
2517oprangeset(ASXTH, t)
2518oprangeset(ASXTHW, t)
2519oprangeset(ASXTW, t)
2520oprangeset(AUXTB, t)
2521oprangeset(AUXTH, t)
2522oprangeset(AUXTW, t)
2523oprangeset(AUXTBW, t)
2524oprangeset(AUXTHW, t)
2525
2526case ACCMN:
2527oprangeset(ACCMNW, t)
2528oprangeset(ACCMP, t)
2529oprangeset(ACCMPW, t)
2530
2531case ACSEL:
2532oprangeset(ACSELW, t)
2533oprangeset(ACSINC, t)
2534oprangeset(ACSINCW, t)
2535oprangeset(ACSINV, t)
2536oprangeset(ACSINVW, t)
2537oprangeset(ACSNEG, t)
2538oprangeset(ACSNEGW, t)
2539
2540case ACINC:
2541// aliases Rm=Rn, !cond
2542oprangeset(ACINCW, t)
2543oprangeset(ACINV, t)
2544oprangeset(ACINVW, t)
2545oprangeset(ACNEG, t)
2546oprangeset(ACNEGW, t)
2547
2548// aliases, Rm=Rn=REGZERO, !cond
2549case ACSET:
2550oprangeset(ACSETW, t)
2551
2552oprangeset(ACSETM, t)
2553oprangeset(ACSETMW, t)
2554
2555case AMOVD,
2556AMOVBU,
2557AB,
2558ABL,
2559AWORD,
2560ADWORD,
2561obj.ARET,
2562obj.ATEXT:
2563break
2564
2565case ALDP:
2566oprangeset(AFLDPD, t)
2567
2568case ASTP:
2569oprangeset(AFSTPD, t)
2570
2571case ASTPW:
2572oprangeset(AFSTPS, t)
2573
2574case ALDPW:
2575oprangeset(ALDPSW, t)
2576oprangeset(AFLDPS, t)
2577
2578case AERET:
2579oprangeset(AWFE, t)
2580oprangeset(AWFI, t)
2581oprangeset(AYIELD, t)
2582oprangeset(ASEV, t)
2583oprangeset(ASEVL, t)
2584oprangeset(ANOOP, t)
2585oprangeset(ADRPS, t)
2586
2587case ACBZ:
2588oprangeset(ACBZW, t)
2589oprangeset(ACBNZ, t)
2590oprangeset(ACBNZW, t)
2591
2592case ATBZ:
2593oprangeset(ATBNZ, t)
2594
2595case AADR, AADRP:
2596break
2597
2598case ACLREX:
2599break
2600
2601case ASVC:
2602oprangeset(AHVC, t)
2603oprangeset(AHLT, t)
2604oprangeset(ASMC, t)
2605oprangeset(ABRK, t)
2606oprangeset(ADCPS1, t)
2607oprangeset(ADCPS2, t)
2608oprangeset(ADCPS3, t)
2609
2610case AFADDS:
2611oprangeset(AFADDD, t)
2612oprangeset(AFSUBS, t)
2613oprangeset(AFSUBD, t)
2614oprangeset(AFMULS, t)
2615oprangeset(AFMULD, t)
2616oprangeset(AFNMULS, t)
2617oprangeset(AFNMULD, t)
2618oprangeset(AFDIVS, t)
2619oprangeset(AFMAXD, t)
2620oprangeset(AFMAXS, t)
2621oprangeset(AFMIND, t)
2622oprangeset(AFMINS, t)
2623oprangeset(AFMAXNMD, t)
2624oprangeset(AFMAXNMS, t)
2625oprangeset(AFMINNMD, t)
2626oprangeset(AFMINNMS, t)
2627oprangeset(AFDIVD, t)
2628
2629case AFMSUBD:
2630oprangeset(AFMSUBS, t)
2631oprangeset(AFMADDS, t)
2632oprangeset(AFMADDD, t)
2633oprangeset(AFNMSUBS, t)
2634oprangeset(AFNMSUBD, t)
2635oprangeset(AFNMADDS, t)
2636oprangeset(AFNMADDD, t)
2637
2638case AFCVTSD:
2639oprangeset(AFCVTDS, t)
2640oprangeset(AFABSD, t)
2641oprangeset(AFABSS, t)
2642oprangeset(AFNEGD, t)
2643oprangeset(AFNEGS, t)
2644oprangeset(AFSQRTD, t)
2645oprangeset(AFSQRTS, t)
2646oprangeset(AFRINTNS, t)
2647oprangeset(AFRINTND, t)
2648oprangeset(AFRINTPS, t)
2649oprangeset(AFRINTPD, t)
2650oprangeset(AFRINTMS, t)
2651oprangeset(AFRINTMD, t)
2652oprangeset(AFRINTZS, t)
2653oprangeset(AFRINTZD, t)
2654oprangeset(AFRINTAS, t)
2655oprangeset(AFRINTAD, t)
2656oprangeset(AFRINTXS, t)
2657oprangeset(AFRINTXD, t)
2658oprangeset(AFRINTIS, t)
2659oprangeset(AFRINTID, t)
2660oprangeset(AFCVTDH, t)
2661oprangeset(AFCVTHS, t)
2662oprangeset(AFCVTHD, t)
2663oprangeset(AFCVTSH, t)
2664
2665case AFCMPS:
2666oprangeset(AFCMPD, t)
2667oprangeset(AFCMPES, t)
2668oprangeset(AFCMPED, t)
2669
2670case AFCCMPS:
2671oprangeset(AFCCMPD, t)
2672oprangeset(AFCCMPES, t)
2673oprangeset(AFCCMPED, t)
2674
2675case AFCSELD:
2676oprangeset(AFCSELS, t)
2677
2678case AFMOVS, AFMOVD, AFMOVQ:
2679break
2680
2681case AFCVTZSD:
2682oprangeset(AFCVTZSDW, t)
2683oprangeset(AFCVTZSS, t)
2684oprangeset(AFCVTZSSW, t)
2685oprangeset(AFCVTZUD, t)
2686oprangeset(AFCVTZUDW, t)
2687oprangeset(AFCVTZUS, t)
2688oprangeset(AFCVTZUSW, t)
2689
2690case ASCVTFD:
2691oprangeset(ASCVTFS, t)
2692oprangeset(ASCVTFWD, t)
2693oprangeset(ASCVTFWS, t)
2694oprangeset(AUCVTFD, t)
2695oprangeset(AUCVTFS, t)
2696oprangeset(AUCVTFWD, t)
2697oprangeset(AUCVTFWS, t)
2698
2699case ASYS:
2700oprangeset(AAT, t)
2701oprangeset(ADC, t)
2702oprangeset(AIC, t)
2703oprangeset(ATLBI, t)
2704
2705case ASYSL, AHINT:
2706break
2707
2708case ADMB:
2709oprangeset(ADSB, t)
2710oprangeset(AISB, t)
2711
2712case AMRS, AMSR:
2713break
2714
2715case ALDAR:
2716oprangeset(ALDARW, t)
2717oprangeset(ALDARB, t)
2718oprangeset(ALDARH, t)
2719fallthrough
2720
2721case ALDXR:
2722oprangeset(ALDXRB, t)
2723oprangeset(ALDXRH, t)
2724oprangeset(ALDXRW, t)
2725
2726case ALDAXR:
2727oprangeset(ALDAXRB, t)
2728oprangeset(ALDAXRH, t)
2729oprangeset(ALDAXRW, t)
2730
2731case ALDXP:
2732oprangeset(ALDXPW, t)
2733oprangeset(ALDAXP, t)
2734oprangeset(ALDAXPW, t)
2735
2736case ASTLR:
2737oprangeset(ASTLRB, t)
2738oprangeset(ASTLRH, t)
2739oprangeset(ASTLRW, t)
2740
2741case ASTXR:
2742oprangeset(ASTXRB, t)
2743oprangeset(ASTXRH, t)
2744oprangeset(ASTXRW, t)
2745
2746case ASTLXR:
2747oprangeset(ASTLXRB, t)
2748oprangeset(ASTLXRH, t)
2749oprangeset(ASTLXRW, t)
2750
2751case ASTXP:
2752oprangeset(ASTLXP, t)
2753oprangeset(ASTLXPW, t)
2754oprangeset(ASTXPW, t)
2755
2756case AVADDP:
2757oprangeset(AVAND, t)
2758oprangeset(AVCMEQ, t)
2759oprangeset(AVORR, t)
2760oprangeset(AVEOR, t)
2761oprangeset(AVBSL, t)
2762oprangeset(AVBIT, t)
2763oprangeset(AVCMTST, t)
2764oprangeset(AVUZP1, t)
2765oprangeset(AVUZP2, t)
2766oprangeset(AVBIF, t)
2767
2768case AVADD:
2769oprangeset(AVSUB, t)
2770
2771case AAESD:
2772oprangeset(AAESE, t)
2773oprangeset(AAESMC, t)
2774oprangeset(AAESIMC, t)
2775oprangeset(ASHA1SU1, t)
2776oprangeset(ASHA256SU0, t)
2777oprangeset(ASHA512SU0, t)
2778
2779case ASHA1C:
2780oprangeset(ASHA1P, t)
2781oprangeset(ASHA1M, t)
2782
2783case ASHA256H:
2784oprangeset(ASHA256H2, t)
2785oprangeset(ASHA512H, t)
2786oprangeset(ASHA512H2, t)
2787
2788case ASHA1SU0:
2789oprangeset(ASHA256SU1, t)
2790oprangeset(ASHA512SU1, t)
2791
2792case AVADDV:
2793oprangeset(AVUADDLV, t)
2794
2795case AVFMLA:
2796oprangeset(AVFMLS, t)
2797
2798case AVPMULL:
2799oprangeset(AVPMULL2, t)
2800
2801case AVUSHR:
2802oprangeset(AVSHL, t)
2803oprangeset(AVSRI, t)
2804
2805case AVREV32:
2806oprangeset(AVCNT, t)
2807oprangeset(AVRBIT, t)
2808oprangeset(AVREV64, t)
2809oprangeset(AVREV16, t)
2810
2811case AVZIP1:
2812oprangeset(AVZIP2, t)
2813
2814case AVUXTL:
2815oprangeset(AVUXTL2, t)
2816
2817case AVUSHLL:
2818oprangeset(AVUSHLL2, t)
2819
2820case AVLD1R:
2821oprangeset(AVLD2, t)
2822oprangeset(AVLD2R, t)
2823oprangeset(AVLD3, t)
2824oprangeset(AVLD3R, t)
2825oprangeset(AVLD4, t)
2826oprangeset(AVLD4R, t)
2827
2828case ASHA1H,
2829AVCNT,
2830AVMOV,
2831AVLD1,
2832AVST1,
2833AVST2,
2834AVST3,
2835AVST4,
2836AVTBL,
2837AVDUP,
2838AVMOVI,
2839APRFM,
2840AVEXT:
2841break
2842
2843case obj.ANOP,
2844obj.AUNDEF,
2845obj.AFUNCDATA,
2846obj.APCALIGN,
2847obj.APCDATA,
2848obj.ADUFFZERO,
2849obj.ADUFFCOPY:
2850break
2851}
2852}
2853}
2854
2855// chipfloat7() checks if the immediate constants available in FMOVS/FMOVD instructions.
2856// For details of the range of constants available, see
2857// http://infocenter.arm.com/help/topic/com.arm.doc.dui0473m/dom1359731199385.html.
2858func (c *ctxt7) chipfloat7(e float64) int {
2859ei := math.Float64bits(e)
2860l := uint32(int32(ei))
2861h := uint32(int32(ei >> 32))
2862
2863if l != 0 || h&0xffff != 0 {
2864return -1
2865}
2866h1 := h & 0x7fc00000
2867if h1 != 0x40000000 && h1 != 0x3fc00000 {
2868return -1
2869}
2870n := 0
2871
2872// sign bit (a)
2873if h&0x80000000 != 0 {
2874n |= 1 << 7
2875}
2876
2877// exp sign bit (b)
2878if h1 == 0x3fc00000 {
2879n |= 1 << 6
2880}
2881
2882// rest of exp and mantissa (cd-efgh)
2883n |= int((h >> 16) & 0x3f)
2884
2885//print("match %.8lux %.8lux %d\n", l, h, n);
2886return n
2887}
2888
2889/* form offset parameter to SYS; special register number */
2890func SYSARG5(op0 int, op1 int, Cn int, Cm int, op2 int) int {
2891return op0<<19 | op1<<16 | Cn<<12 | Cm<<8 | op2<<5
2892}
2893
2894func SYSARG4(op1 int, Cn int, Cm int, op2 int) int {
2895return SYSARG5(0, op1, Cn, Cm, op2)
2896}
2897
2898// checkUnpredictable checks if the sourse and transfer registers are the same register.
2899// ARM64 manual says it is "constrained unpredictable" if the src and dst registers of STP/LDP are same.
2900func (c *ctxt7) checkUnpredictable(p *obj.Prog, isload bool, wback bool, rn int16, rt1 int16, rt2 int16) {
2901if wback && rn != REGSP && (rn == rt1 || rn == rt2) {
2902c.ctxt.Diag("constrained unpredictable behavior: %v", p)
2903}
2904if isload && rt1 == rt2 {
2905c.ctxt.Diag("constrained unpredictable behavior: %v", p)
2906}
2907}
2908
2909/* checkindex checks if index >= 0 && index <= maxindex */
2910func (c *ctxt7) checkindex(p *obj.Prog, index, maxindex int) {
2911if index < 0 || index > maxindex {
2912c.ctxt.Diag("register element index out of range 0 to %d: %v", maxindex, p)
2913}
2914}
2915
2916/* checkoffset checks whether the immediate offset is valid for VLD[1-4].P and VST[1-4].P */
2917func (c *ctxt7) checkoffset(p *obj.Prog, as obj.As) {
2918var offset, list, n, expect int64
2919switch as {
2920case AVLD1, AVLD2, AVLD3, AVLD4, AVLD1R, AVLD2R, AVLD3R, AVLD4R:
2921offset = p.From.Offset
2922list = p.To.Offset
2923case AVST1, AVST2, AVST3, AVST4:
2924offset = p.To.Offset
2925list = p.From.Offset
2926default:
2927c.ctxt.Diag("invalid operation on op %v", p.As)
2928}
2929opcode := (list >> 12) & 15
2930q := (list >> 30) & 1
2931size := (list >> 10) & 3
2932if offset == 0 {
2933return
2934}
2935switch opcode {
2936case 0x7:
2937n = 1 // one register
2938case 0xa:
2939n = 2 // two registers
2940case 0x6:
2941n = 3 // three registers
2942case 0x2:
2943n = 4 // four registers
2944default:
2945c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p)
2946}
2947
2948switch as {
2949case AVLD1R, AVLD2R, AVLD3R, AVLD4R:
2950if offset != n*(1<<uint(size)) {
2951c.ctxt.Diag("invalid post-increment offset: %v", p)
2952}
2953default:
2954if !(q == 0 && offset == n*8) && !(q == 1 && offset == n*16) {
2955c.ctxt.Diag("invalid post-increment offset: %v", p)
2956}
2957}
2958
2959switch as {
2960case AVLD1, AVST1:
2961return
2962case AVLD1R:
2963expect = 1
2964case AVLD2, AVST2, AVLD2R:
2965expect = 2
2966case AVLD3, AVST3, AVLD3R:
2967expect = 3
2968case AVLD4, AVST4, AVLD4R:
2969expect = 4
2970}
2971
2972if expect != n {
2973c.ctxt.Diag("expected %d registers, got %d: %v.", expect, n, p)
2974}
2975}
2976
2977/* checkShiftAmount checks whether the index shift amount is valid */
2978/* for load with register offset instructions */
2979func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) {
2980var amount int16
2981amount = (a.Index >> 5) & 7
2982switch p.As {
2983case AMOVB, AMOVBU:
2984if amount != 0 {
2985c.ctxt.Diag("invalid index shift amount: %v", p)
2986}
2987case AMOVH, AMOVHU:
2988if amount != 1 && amount != 0 {
2989c.ctxt.Diag("invalid index shift amount: %v", p)
2990}
2991case AMOVW, AMOVWU, AFMOVS:
2992if amount != 2 && amount != 0 {
2993c.ctxt.Diag("invalid index shift amount: %v", p)
2994}
2995case AMOVD, AFMOVD:
2996if amount != 3 && amount != 0 {
2997c.ctxt.Diag("invalid index shift amount: %v", p)
2998}
2999default:
3000panic("invalid operation")
3001}
3002}
3003
3004func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
3005var os [5]uint32
3006o1 := uint32(0)
3007o2 := uint32(0)
3008o3 := uint32(0)
3009o4 := uint32(0)
3010o5 := uint32(0)
3011if false { /*debug['P']*/
3012fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
3013}
3014switch o.type_ {
3015default:
3016c.ctxt.Diag("%v: unknown asm %d", p, o.type_)
3017
3018case 0: /* pseudo ops */
3019break
3020
3021case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
3022o1 = c.oprrr(p, p.As)
3023
3024rf := int(p.From.Reg)
3025rt := int(p.To.Reg)
3026r := int(p.Reg)
3027if p.To.Type == obj.TYPE_NONE {
3028rt = REGZERO
3029}
3030if r == 0 {
3031r = rt
3032}
3033o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
3034
3035case 2: /* add/sub $(uimm12|uimm24)[,R],R; cmp $(uimm12|uimm24),R */
3036o1 = c.opirr(p, p.As)
3037
3038rt := int(p.To.Reg)
3039if p.To.Type == obj.TYPE_NONE {
3040if (o1 & Sbit) == 0 {
3041c.ctxt.Diag("ineffective ZR destination\n%v", p)
3042}
3043rt = REGZERO
3044}
3045
3046r := int(p.Reg)
3047if r == 0 {
3048r = rt
3049}
3050v := int32(c.regoff(&p.From))
3051o1 = c.oaddi(p, int32(o1), v, r, rt)
3052
3053case 3: /* op R<<n[,R],R (shifted register) */
3054o1 = c.oprrr(p, p.As)
3055
3056amount := (p.From.Offset >> 10) & 63
3057is64bit := o1 & (1 << 31)
3058if is64bit == 0 && amount >= 32 {
3059c.ctxt.Diag("shift amount out of range 0 to 31: %v", p)
3060}
3061o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
3062rt := int(p.To.Reg)
3063if p.To.Type == obj.TYPE_NONE {
3064rt = REGZERO
3065}
3066r := int(p.Reg)
3067if p.As == AMVN || p.As == AMVNW {
3068r = REGZERO
3069} else if r == 0 {
3070r = rt
3071}
3072o1 |= (uint32(r&31) << 5) | uint32(rt&31)
3073
3074case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R; mov $addcon2, R */
3075rt := int(p.To.Reg)
3076r := int(o.param)
3077
3078if r == 0 {
3079r = REGZERO
3080} else if r == REGFROM {
3081r = int(p.From.Reg)
3082}
3083if r == 0 {
3084r = REGSP
3085}
3086
3087v := int32(c.regoff(&p.From))
3088var op int32
3089if v < 0 {
3090v = -v
3091op = int32(c.opirr(p, ASUB))
3092} else {
3093op = int32(c.opirr(p, AADD))
3094}
3095
3096if int(o.size) == 8 {
3097o1 = c.oaddi(p, op, v&0xfff000, r, REGTMP)
3098o2 = c.oaddi(p, op, v&0x000fff, REGTMP, rt)
3099break
3100}
3101
3102o1 = c.oaddi(p, op, v, r, rt)
3103
3104case 5: /* b s; bl s */
3105o1 = c.opbra(p, p.As)
3106
3107if p.To.Sym == nil {
3108o1 |= uint32(c.brdist(p, 0, 26, 2))
3109break
3110}
3111
3112rel := obj.Addrel(c.cursym)
3113rel.Off = int32(c.pc)
3114rel.Siz = 4
3115rel.Sym = p.To.Sym
3116rel.Add = p.To.Offset
3117rel.Type = objabi.R_CALLARM64
3118
3119case 6: /* b ,O(R); bl ,O(R) */
3120o1 = c.opbrr(p, p.As)
3121
3122o1 |= uint32(p.To.Reg&31) << 5
3123rel := obj.Addrel(c.cursym)
3124rel.Off = int32(c.pc)
3125rel.Siz = 0
3126rel.Type = objabi.R_CALLIND
3127
3128case 7: /* beq s */
3129o1 = c.opbra(p, p.As)
3130
3131o1 |= uint32(c.brdist(p, 0, 19, 2) << 5)
3132
3133case 8: /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */
3134rt := int(p.To.Reg)
3135
3136rf := int(p.Reg)
3137if rf == 0 {
3138rf = rt
3139}
3140v := int32(p.From.Offset)
3141switch p.As {
3142case AASR:
3143o1 = c.opbfm(p, ASBFM, int(v), 63, rf, rt)
3144
3145case AASRW:
3146o1 = c.opbfm(p, ASBFMW, int(v), 31, rf, rt)
3147
3148case ALSL:
3149o1 = c.opbfm(p, AUBFM, int((64-v)&63), int(63-v), rf, rt)
3150
3151case ALSLW:
3152o1 = c.opbfm(p, AUBFMW, int((32-v)&31), int(31-v), rf, rt)
3153
3154case ALSR:
3155o1 = c.opbfm(p, AUBFM, int(v), 63, rf, rt)
3156
3157case ALSRW:
3158o1 = c.opbfm(p, AUBFMW, int(v), 31, rf, rt)
3159
3160case AROR:
3161o1 = c.opextr(p, AEXTR, v, rf, rf, rt)
3162
3163case ARORW:
3164o1 = c.opextr(p, AEXTRW, v, rf, rf, rt)
3165
3166default:
3167c.ctxt.Diag("bad shift $con\n%v", p)
3168break
3169}
3170
3171case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
3172o1 = c.oprrr(p, p.As)
3173
3174r := int(p.Reg)
3175if r == 0 {
3176r = int(p.To.Reg)
3177}
3178o1 |= (uint32(p.From.Reg&31) << 16) | (uint32(r&31) << 5) | uint32(p.To.Reg&31)
3179
3180case 10: /* brk/hvc/.../svc [$con] */
3181o1 = c.opimm(p, p.As)
3182
3183if p.From.Type != obj.TYPE_NONE {
3184o1 |= uint32((p.From.Offset & 0xffff) << 5)
3185}
3186
3187case 11: /* dword */
3188c.aclass(&p.To)
3189
3190o1 = uint32(c.instoffset)
3191o2 = uint32(c.instoffset >> 32)
3192if p.To.Sym != nil {
3193rel := obj.Addrel(c.cursym)
3194rel.Off = int32(c.pc)
3195rel.Siz = 8
3196rel.Sym = p.To.Sym
3197rel.Add = p.To.Offset
3198rel.Type = objabi.R_ADDR
3199o2 = 0
3200o1 = o2
3201}
3202
3203case 12: /* movT $vcon, reg */
3204// NOTE: this case does not use REGTMP. If it ever does,
3205// remove the NOTUSETMP flag in optab.
3206num := c.omovlconst(p.As, p, &p.From, int(p.To.Reg), os[:])
3207if num == 0 {
3208c.ctxt.Diag("invalid constant: %v", p)
3209}
3210o1 = os[0]
3211o2 = os[1]
3212o3 = os[2]
3213o4 = os[3]
3214
3215case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
3216o := uint32(0)
3217num := uint8(0)
3218cls := oclass(&p.From)
3219if isADDWop(p.As) {
3220if !cmp(C_LCON, cls) {
3221c.ctxt.Diag("illegal combination: %v", p)
3222}
3223num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
3224} else {
3225num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
3226}
3227if num == 0 {
3228c.ctxt.Diag("invalid constant: %v", p)
3229}
3230rt := int(p.To.Reg)
3231if p.To.Type == obj.TYPE_NONE {
3232rt = REGZERO
3233}
3234r := int(p.Reg)
3235if r == 0 {
3236r = rt
3237}
3238if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
3239o = c.opxrrr(p, p.As, false)
3240o |= REGTMP & 31 << 16
3241o |= LSL0_64
3242} else {
3243o = c.oprrr(p, p.As)
3244o |= REGTMP & 31 << 16 /* shift is 0 */
3245}
3246
3247o |= uint32(r&31) << 5
3248o |= uint32(rt & 31)
3249
3250os[num] = o
3251o1 = os[0]
3252o2 = os[1]
3253o3 = os[2]
3254o4 = os[3]
3255o5 = os[4]
3256
3257case 14: /* word */
3258if c.aclass(&p.To) == C_ADDR {
3259c.ctxt.Diag("address constant needs DWORD\n%v", p)
3260}
3261o1 = uint32(c.instoffset)
3262if p.To.Sym != nil {
3263// This case happens with words generated
3264// in the PC stream as part of the literal pool.
3265rel := obj.Addrel(c.cursym)
3266
3267rel.Off = int32(c.pc)
3268rel.Siz = 4
3269rel.Sym = p.To.Sym
3270rel.Add = p.To.Offset
3271rel.Type = objabi.R_ADDR
3272o1 = 0
3273}
3274
3275case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub/fmadd/fmsub/fnmadd/fnmsub Rm,Ra,Rn,Rd */
3276o1 = c.oprrr(p, p.As)
3277
3278rf := int(p.From.Reg)
3279rt := int(p.To.Reg)
3280var r int
3281var ra int
3282if p.From3Type() == obj.TYPE_REG {
3283r = int(p.GetFrom3().Reg)
3284ra = int(p.Reg)
3285if ra == 0 {
3286ra = REGZERO
3287}
3288} else {
3289r = int(p.Reg)
3290if r == 0 {
3291r = rt
3292}
3293ra = REGZERO
3294}
3295
3296o1 |= (uint32(rf&31) << 16) | (uint32(ra&31) << 10) | (uint32(r&31) << 5) | uint32(rt&31)
3297
3298case 16: /* XremY R[,R],R -> XdivY; XmsubY */
3299o1 = c.oprrr(p, p.As)
3300
3301rf := int(p.From.Reg)
3302rt := int(p.To.Reg)
3303r := int(p.Reg)
3304if r == 0 {
3305r = rt
3306}
3307o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | REGTMP&31
3308o2 = c.oprrr(p, AMSUBW)
3309o2 |= o1 & (1 << 31) /* same size */
3310o2 |= (uint32(rf&31) << 16) | (uint32(r&31) << 10) | (REGTMP & 31 << 5) | uint32(rt&31)
3311
3312case 17: /* op Rm,[Rn],Rd; default Rn=ZR */
3313o1 = c.oprrr(p, p.As)
3314
3315rf := int(p.From.Reg)
3316rt := int(p.To.Reg)
3317r := int(p.Reg)
3318if p.To.Type == obj.TYPE_NONE {
3319rt = REGZERO
3320}
3321if r == 0 {
3322r = REGZERO
3323}
3324o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
3325
3326case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */
3327o1 = c.oprrr(p, p.As)
3328
3329cond := int(p.From.Reg)
3330if cond < COND_EQ || cond > COND_NV {
3331c.ctxt.Diag("invalid condition: %v", p)
3332} else {
3333cond -= COND_EQ
3334}
3335
3336r := int(p.Reg)
3337var rf int
3338if r != 0 {
3339if p.From3Type() == obj.TYPE_NONE {
3340/* CINC/CINV/CNEG */
3341rf = r
3342cond ^= 1
3343} else {
3344rf = int(p.GetFrom3().Reg) /* CSEL */
3345}
3346} else {
3347/* CSET */
3348rf = REGZERO
3349r = rf
3350cond ^= 1
3351}
3352
3353rt := int(p.To.Reg)
3354o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(r&31) << 5) | uint32(rt&31)
3355
3356case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
3357nzcv := int(p.To.Offset)
3358
3359cond := int(p.From.Reg)
3360if cond < COND_EQ || cond > COND_NV {
3361c.ctxt.Diag("invalid condition\n%v", p)
3362} else {
3363cond -= COND_EQ
3364}
3365var rf int
3366if p.GetFrom3().Type == obj.TYPE_REG {
3367o1 = c.oprrr(p, p.As)
3368rf = int(p.GetFrom3().Reg) /* Rm */
3369} else {
3370o1 = c.opirr(p, p.As)
3371rf = int(p.GetFrom3().Offset & 0x1F)
3372}
3373
3374o1 |= (uint32(rf&31) << 16) | (uint32(cond&15) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
3375
3376case 20: /* movT R,O(R) -> strT */
3377v := int32(c.regoff(&p.To))
3378sz := int32(1 << uint(movesize(p.As)))
3379
3380r := int(p.To.Reg)
3381if r == 0 {
3382r = int(o.param)
3383}
3384if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
3385o1 = c.olsr9s(p, int32(c.opstr9(p, p.As)), v, r, int(p.From.Reg))
3386} else {
3387v = int32(c.offsetshift(p, int64(v), int(o.a4)))
3388o1 = c.olsr12u(p, int32(c.opstr12(p, p.As)), v, r, int(p.From.Reg))
3389}
3390
3391case 21: /* movT O(R),R -> ldrT */
3392v := int32(c.regoff(&p.From))
3393sz := int32(1 << uint(movesize(p.As)))
3394
3395r := int(p.From.Reg)
3396if r == 0 {
3397r = int(o.param)
3398}
3399if v < 0 || v%sz != 0 { /* unscaled 9-bit signed */
3400o1 = c.olsr9s(p, int32(c.opldr9(p, p.As)), v, r, int(p.To.Reg))
3401} else {
3402v = int32(c.offsetshift(p, int64(v), int(o.a1)))
3403//print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
3404o1 = c.olsr12u(p, int32(c.opldr12(p, p.As)), v, r, int(p.To.Reg))
3405}
3406
3407case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
3408if p.From.Reg != REGSP && p.From.Reg == p.To.Reg {
3409c.ctxt.Diag("constrained unpredictable behavior: %v", p)
3410}
3411
3412v := int32(p.From.Offset)
3413
3414if v < -256 || v > 255 {
3415c.ctxt.Diag("offset out of range [-255,254]: %v", p)
3416}
3417o1 = c.opldrpp(p, p.As)
3418if o.scond == C_XPOST {
3419o1 |= 1 << 10
3420} else {
3421o1 |= 3 << 10
3422}
3423o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.From.Reg&31) << 5) | uint32(p.To.Reg&31)
3424
3425case 23: /* movT R,(R)O!; movT O(R)!, R -> strT */
3426if p.To.Reg != REGSP && p.From.Reg == p.To.Reg {
3427c.ctxt.Diag("constrained unpredictable behavior: %v", p)
3428}
3429
3430v := int32(p.To.Offset)
3431
3432if v < -256 || v > 255 {
3433c.ctxt.Diag("offset out of range [-255,254]: %v", p)
3434}
3435o1 = LD2STR(c.opldrpp(p, p.As))
3436if o.scond == C_XPOST {
3437o1 |= 1 << 10
3438} else {
3439o1 |= 3 << 10
3440}
3441o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.To.Reg&31) << 5) | uint32(p.From.Reg&31)
3442
3443case 24: /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */
3444rf := int(p.From.Reg)
3445rt := int(p.To.Reg)
3446s := rf == REGSP || rt == REGSP
3447if p.As == AMVN || p.As == AMVNW {
3448if s {
3449c.ctxt.Diag("illegal SP reference\n%v", p)
3450}
3451o1 = c.oprrr(p, p.As)
3452o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
3453} else if s {
3454o1 = c.opirr(p, p.As)
3455o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
3456} else {
3457o1 = c.oprrr(p, p.As)
3458o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
3459}
3460
3461case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */
3462o1 = c.oprrr(p, p.As)
3463
3464rf := int(p.From.Reg)
3465if rf == C_NONE {
3466rf = int(p.To.Reg)
3467}
3468rt := int(p.To.Reg)
3469o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
3470
3471case 26: /* negX Rm<<s, Rd -> subX Rm<<s, ZR, Rd */
3472o1 = c.oprrr(p, p.As)
3473
3474o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
3475rt := int(p.To.Reg)
3476o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
3477
3478case 27: /* op Rm<<n[,Rn],Rd (extended register) */
3479if (p.From.Reg-obj.RBaseARM64)®_EXT != 0 {
3480amount := (p.From.Reg >> 5) & 7
3481if amount > 4 {
3482c.ctxt.Diag("shift amount out of range 0 to 4: %v", p)
3483}
3484o1 = c.opxrrr(p, p.As, true)
3485o1 |= c.encRegShiftOrExt(&p.From, p.From.Reg) /* includes reg, op, etc */
3486} else {
3487o1 = c.opxrrr(p, p.As, false)
3488o1 |= uint32(p.From.Reg&31) << 16
3489}
3490rt := int(p.To.Reg)
3491if p.To.Type == obj.TYPE_NONE {
3492rt = REGZERO
3493}
3494r := int(p.Reg)
3495if r == 0 {
3496r = rt
3497}
3498o1 |= (uint32(r&31) << 5) | uint32(rt&31)
3499
3500case 28: /* logop $vcon, [R], R (64 bit literal) */
3501o := uint32(0)
3502num := uint8(0)
3503cls := oclass(&p.From)
3504if isANDWop(p.As) {
3505if !cmp(C_LCON, cls) {
3506c.ctxt.Diag("illegal combination: %v", p)
3507}
3508num = c.omovlconst(AMOVW, p, &p.From, REGTMP, os[:])
3509} else {
3510num = c.omovlconst(AMOVD, p, &p.From, REGTMP, os[:])
3511}
3512
3513if num == 0 {
3514c.ctxt.Diag("invalid constant: %v", p)
3515}
3516rt := int(p.To.Reg)
3517if p.To.Type == obj.TYPE_NONE {
3518rt = REGZERO
3519}
3520r := int(p.Reg)
3521if r == 0 {
3522r = rt
3523}
3524o = c.oprrr(p, p.As)
3525o |= REGTMP & 31 << 16 /* shift is 0 */
3526o |= uint32(r&31) << 5
3527o |= uint32(rt & 31)
3528
3529os[num] = o
3530o1 = os[0]
3531o2 = os[1]
3532o3 = os[2]
3533o4 = os[3]
3534o5 = os[4]
3535
3536case 29: /* op Rn, Rd */
3537fc := c.aclass(&p.From)
3538tc := c.aclass(&p.To)
3539if (p.As == AFMOVD || p.As == AFMOVS) && (fc == C_REG || fc == C_ZCON || tc == C_REG || tc == C_ZCON) {
3540// FMOV Rx, Fy or FMOV Fy, Rx
3541o1 = FPCVTI(0, 0, 0, 0, 6)
3542if p.As == AFMOVD {
3543o1 |= 1<<31 | 1<<22 // 64-bit
3544}
3545if fc == C_REG || fc == C_ZCON {
3546o1 |= 1 << 16 // FMOV Rx, Fy
3547}
3548} else {
3549o1 = c.oprrr(p, p.As)
3550}
3551o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31)
3552
3553case 30: /* movT R,L(R) -> strT */
3554// if offset L can be split into hi+lo, and both fit into instructions, do
3555// add $hi, R, Rtmp
3556// str R, lo(Rtmp)
3557// otherwise, use constant pool
3558// mov $L, Rtmp (from constant pool)
3559// str R, (R+Rtmp)
3560s := movesize(o.as)
3561if s < 0 {
3562c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
3563}
3564
3565r := int(p.To.Reg)
3566if r == 0 {
3567r = int(o.param)
3568}
3569
3570v := int32(c.regoff(&p.To))
3571var hi int32
3572if v < 0 || (v&((1<<uint(s))-1)) != 0 {
3573// negative or unaligned offset, use constant pool
3574goto storeusepool
3575}
3576
3577hi = v - (v & (0xFFF << uint(s)))
3578if hi&0xFFF != 0 {
3579c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
3580}
3581if hi&^0xFFF000 != 0 {
3582// hi doesn't fit into an ADD instruction
3583goto storeusepool
3584}
3585
3586o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
3587o2 = c.olsr12u(p, int32(c.opstr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
3588break
3589
3590storeusepool:
3591if r == REGTMP || p.From.Reg == REGTMP {
3592c.ctxt.Diag("REGTMP used in large offset store: %v", p)
3593}
3594o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
3595o2 = c.olsxrr(p, int32(c.opstrr(p, p.As, false)), int(p.From.Reg), r, REGTMP)
3596
3597case 31: /* movT L(R), R -> ldrT */
3598// if offset L can be split into hi+lo, and both fit into instructions, do
3599// add $hi, R, Rtmp
3600// ldr lo(Rtmp), R
3601// otherwise, use constant pool
3602// mov $L, Rtmp (from constant pool)
3603// ldr (R+Rtmp), R
3604s := movesize(o.as)
3605if s < 0 {
3606c.ctxt.Diag("unexpected long move, op %v tab %v\n%v", p.As, o.as, p)
3607}
3608
3609r := int(p.From.Reg)
3610if r == 0 {
3611r = int(o.param)
3612}
3613
3614v := int32(c.regoff(&p.From))
3615var hi int32
3616if v < 0 || (v&((1<<uint(s))-1)) != 0 {
3617// negative or unaligned offset, use constant pool
3618goto loadusepool
3619}
3620
3621hi = v - (v & (0xFFF << uint(s)))
3622if (hi & 0xFFF) != 0 {
3623c.ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
3624}
3625if hi&^0xFFF000 != 0 {
3626// hi doesn't fit into an ADD instruction
3627goto loadusepool
3628}
3629
3630o1 = c.oaddi(p, int32(c.opirr(p, AADD)), hi, r, REGTMP)
3631o2 = c.olsr12u(p, int32(c.opldr12(p, p.As)), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
3632break
3633
3634loadusepool:
3635if r == REGTMP || p.From.Reg == REGTMP {
3636c.ctxt.Diag("REGTMP used in large offset load: %v", p)
3637}
3638o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
3639o2 = c.olsxrr(p, int32(c.opldrr(p, p.As, false)), int(p.To.Reg), r, REGTMP)
3640
3641case 32: /* mov $con, R -> movz/movn */
3642o1 = c.omovconst(p.As, p, &p.From, int(p.To.Reg))
3643
3644case 33: /* movk $uimm16 << pos */
3645o1 = c.opirr(p, p.As)
3646
3647d := p.From.Offset
3648s := movcon(d)
3649if s < 0 || s >= 4 {
3650c.ctxt.Diag("bad constant for MOVK: %#x\n%v", uint64(d), p)
3651}
3652if (o1&S64) == 0 && s >= 2 {
3653c.ctxt.Diag("illegal bit position\n%v", p)
3654}
3655if ((d >> uint(s*16)) >> 16) != 0 {
3656c.ctxt.Diag("requires uimm16\n%v", p)
3657}
3658rt := int(p.To.Reg)
3659
3660o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
3661
3662case 34: /* mov $lacon,R */
3663o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
3664
3665if o1 == 0 {
3666break
3667}
3668o2 = c.opxrrr(p, AADD, false)
3669o2 |= REGTMP & 31 << 16
3670o2 |= LSL0_64
3671r := int(p.From.Reg)
3672if r == 0 {
3673r = int(o.param)
3674}
3675o2 |= uint32(r&31) << 5
3676o2 |= uint32(p.To.Reg & 31)
3677
3678case 35: /* mov SPR,R -> mrs */
3679o1 = c.oprrr(p, AMRS)
3680
3681// SysRegEnc function returns the system register encoding and accessFlags.
3682_, v, accessFlags := SysRegEnc(p.From.Reg)
3683if v == 0 {
3684c.ctxt.Diag("illegal system register:\n%v", p)
3685}
3686if (o1 & (v &^ (3 << 19))) != 0 {
3687c.ctxt.Diag("MRS register value overlap\n%v", p)
3688}
3689if accessFlags&SR_READ == 0 {
3690c.ctxt.Diag("system register is not readable: %v", p)
3691}
3692
3693o1 |= v
3694o1 |= uint32(p.To.Reg & 31)
3695
3696case 36: /* mov R,SPR */
3697o1 = c.oprrr(p, AMSR)
3698
3699// SysRegEnc function returns the system register encoding and accessFlags.
3700_, v, accessFlags := SysRegEnc(p.To.Reg)
3701if v == 0 {
3702c.ctxt.Diag("illegal system register:\n%v", p)
3703}
3704if (o1 & (v &^ (3 << 19))) != 0 {
3705c.ctxt.Diag("MSR register value overlap\n%v", p)
3706}
3707if accessFlags&SR_WRITE == 0 {
3708c.ctxt.Diag("system register is not writable: %v", p)
3709}
3710
3711o1 |= v
3712o1 |= uint32(p.From.Reg & 31)
3713
3714case 37: /* mov $con,PSTATEfield -> MSR [immediate] */
3715if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 {
3716c.ctxt.Diag("illegal immediate for PSTATE field\n%v", p)
3717}
3718o1 = c.opirr(p, AMSR)
3719o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
3720v := uint32(0)
3721for i := 0; i < len(pstatefield); i++ {
3722if pstatefield[i].reg == p.To.Reg {
3723v = pstatefield[i].enc
3724break
3725}
3726}
3727
3728if v == 0 {
3729c.ctxt.Diag("illegal PSTATE field for immediate move\n%v", p)
3730}
3731o1 |= v
3732
3733case 38: /* clrex [$imm] */
3734o1 = c.opimm(p, p.As)
3735
3736if p.To.Type == obj.TYPE_NONE {
3737o1 |= 0xF << 8
3738} else {
3739o1 |= uint32((p.To.Offset & 0xF) << 8)
3740}
3741
3742case 39: /* cbz R, rel */
3743o1 = c.opirr(p, p.As)
3744
3745o1 |= uint32(p.From.Reg & 31)
3746o1 |= uint32(c.brdist(p, 0, 19, 2) << 5)
3747
3748case 40: /* tbz */
3749o1 = c.opirr(p, p.As)
3750
3751v := int32(p.From.Offset)
3752if v < 0 || v > 63 {
3753c.ctxt.Diag("illegal bit number\n%v", p)
3754}
3755o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19)
3756o1 |= uint32(c.brdist(p, 0, 14, 2) << 5)
3757o1 |= uint32(p.Reg & 31)
3758
3759case 41: /* eret, nop, others with no operands */
3760o1 = c.op0(p, p.As)
3761
3762case 42: /* bfm R,r,s,R */
3763o1 = c.opbfm(p, p.As, int(p.From.Offset), int(p.GetFrom3().Offset), int(p.Reg), int(p.To.Reg))
3764
3765case 43: /* bfm aliases */
3766r := int(p.From.Offset)
3767s := int(p.GetFrom3().Offset)
3768rf := int(p.Reg)
3769rt := int(p.To.Reg)
3770if rf == 0 {
3771rf = rt
3772}
3773switch p.As {
3774case ABFI:
3775if r != 0 {
3776r = 64 - r
3777}
3778o1 = c.opbfm(p, ABFM, r, s-1, rf, rt)
3779
3780case ABFIW:
3781if r != 0 {
3782r = 32 - r
3783}
3784o1 = c.opbfm(p, ABFMW, r, s-1, rf, rt)
3785
3786case ABFXIL:
3787o1 = c.opbfm(p, ABFM, r, r+s-1, rf, rt)
3788
3789case ABFXILW:
3790o1 = c.opbfm(p, ABFMW, r, r+s-1, rf, rt)
3791
3792case ASBFIZ:
3793if r != 0 {
3794r = 64 - r
3795}
3796o1 = c.opbfm(p, ASBFM, r, s-1, rf, rt)
3797
3798case ASBFIZW:
3799if r != 0 {
3800r = 32 - r
3801}
3802o1 = c.opbfm(p, ASBFMW, r, s-1, rf, rt)
3803
3804case ASBFX:
3805o1 = c.opbfm(p, ASBFM, r, r+s-1, rf, rt)
3806
3807case ASBFXW:
3808o1 = c.opbfm(p, ASBFMW, r, r+s-1, rf, rt)
3809
3810case AUBFIZ:
3811if r != 0 {
3812r = 64 - r
3813}
3814o1 = c.opbfm(p, AUBFM, r, s-1, rf, rt)
3815
3816case AUBFIZW:
3817if r != 0 {
3818r = 32 - r
3819}
3820o1 = c.opbfm(p, AUBFMW, r, s-1, rf, rt)
3821
3822case AUBFX:
3823o1 = c.opbfm(p, AUBFM, r, r+s-1, rf, rt)
3824
3825case AUBFXW:
3826o1 = c.opbfm(p, AUBFMW, r, r+s-1, rf, rt)
3827
3828default:
3829c.ctxt.Diag("bad bfm alias\n%v", p)
3830break
3831}
3832
3833case 44: /* extr $b, Rn, Rm, Rd */
3834o1 = c.opextr(p, p.As, int32(p.From.Offset), int(p.GetFrom3().Reg), int(p.Reg), int(p.To.Reg))
3835
3836case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */
3837rf := int(p.From.Reg)
3838
3839rt := int(p.To.Reg)
3840as := p.As
3841if rf == REGZERO {
3842as = AMOVWU /* clearer in disassembly */
3843}
3844switch as {
3845case AMOVB, ASXTB:
3846o1 = c.opbfm(p, ASBFM, 0, 7, rf, rt)
3847
3848case AMOVH, ASXTH:
3849o1 = c.opbfm(p, ASBFM, 0, 15, rf, rt)
3850
3851case AMOVW, ASXTW:
3852o1 = c.opbfm(p, ASBFM, 0, 31, rf, rt)
3853
3854case AMOVBU, AUXTB:
3855o1 = c.opbfm(p, AUBFM, 0, 7, rf, rt)
3856
3857case AMOVHU, AUXTH:
3858o1 = c.opbfm(p, AUBFM, 0, 15, rf, rt)
3859
3860case AMOVWU:
3861o1 = c.oprrr(p, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
3862
3863case AUXTW:
3864o1 = c.opbfm(p, AUBFM, 0, 31, rf, rt)
3865
3866case ASXTBW:
3867o1 = c.opbfm(p, ASBFMW, 0, 7, rf, rt)
3868
3869case ASXTHW:
3870o1 = c.opbfm(p, ASBFMW, 0, 15, rf, rt)
3871
3872case AUXTBW:
3873o1 = c.opbfm(p, AUBFMW, 0, 7, rf, rt)
3874
3875case AUXTHW:
3876o1 = c.opbfm(p, AUBFMW, 0, 15, rf, rt)
3877
3878default:
3879c.ctxt.Diag("bad sxt %v", as)
3880break
3881}
3882
3883case 46: /* cls */
3884o1 = c.opbit(p, p.As)
3885
3886o1 |= uint32(p.From.Reg&31) << 5
3887o1 |= uint32(p.To.Reg & 31)
3888
3889case 47: /* SWPx/LDADDx/LDANDx/LDEORx/LDORx Rs, (Rb), Rt */
3890rs := p.From.Reg
3891rt := p.RegTo2
3892rb := p.To.Reg
3893
3894fields := atomicInstructions[p.As]
3895// rt can't be sp. rt can't be r31 when field A is 0, A bit is the 23rd bit.
3896if rt == REG_RSP || (rt == REGZERO && (fields&(1<<23) == 0)) {
3897c.ctxt.Diag("illegal destination register: %v\n", p)
3898}
3899o1 |= fields | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
3900
3901case 48: /* ADD $C_ADDCON2, Rm, Rd */
3902// NOTE: this case does not use REGTMP. If it ever does,
3903// remove the NOTUSETMP flag in optab.
3904op := c.opirr(p, p.As)
3905if op&Sbit != 0 {
3906c.ctxt.Diag("can not break addition/subtraction when S bit is set", p)
3907}
3908rt := int(p.To.Reg)
3909r := int(p.Reg)
3910if r == 0 {
3911r = rt
3912}
3913o1 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0x000fff, r, rt)
3914o2 = c.oaddi(p, int32(op), int32(c.regoff(&p.From))&0xfff000, rt, rt)
3915
3916case 50: /* sys/sysl */
3917o1 = c.opirr(p, p.As)
3918
3919if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 {
3920c.ctxt.Diag("illegal SYS argument\n%v", p)
3921}
3922o1 |= uint32(p.From.Offset)
3923if p.To.Type == obj.TYPE_REG {
3924o1 |= uint32(p.To.Reg & 31)
3925} else if p.Reg != 0 {
3926o1 |= uint32(p.Reg & 31)
3927} else {
3928o1 |= 0x1F
3929}
3930
3931case 51: /* dmb */
3932o1 = c.opirr(p, p.As)
3933
3934if p.From.Type == obj.TYPE_CONST {
3935o1 |= uint32((p.From.Offset & 0xF) << 8)
3936}
3937
3938case 52: /* hint */
3939o1 = c.opirr(p, p.As)
3940
3941o1 |= uint32((p.From.Offset & 0x7F) << 5)
3942
3943case 53: /* and/or/eor/bic/tst/... $bitcon, Rn, Rd */
3944a := p.As
3945rt := int(p.To.Reg)
3946if p.To.Type == obj.TYPE_NONE {
3947rt = REGZERO
3948}
3949r := int(p.Reg)
3950if r == 0 {
3951r = rt
3952}
3953mode := 64
3954v := uint64(p.From.Offset)
3955switch p.As {
3956case AANDW, AORRW, AEORW, AANDSW, ATSTW:
3957mode = 32
3958case ABIC, AORN, AEON, ABICS:
3959v = ^v
3960case ABICW, AORNW, AEONW, ABICSW:
3961v = ^v
3962mode = 32
3963}
3964o1 = c.opirr(p, a)
3965o1 |= bitconEncode(v, mode) | uint32(r&31)<<5 | uint32(rt&31)
3966
3967case 54: /* floating point arith */
3968o1 = c.oprrr(p, p.As)
3969rf := int(p.From.Reg)
3970rt := int(p.To.Reg)
3971r := int(p.Reg)
3972if (o1&(0x1F<<24)) == (0x1E<<24) && (o1&(1<<11)) == 0 { /* monadic */
3973r = rf
3974rf = 0
3975} else if r == 0 {
3976r = rt
3977}
3978o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
3979
3980case 55: /* floating-point constant */
3981var rf int
3982o1 = 0xf<<25 | 1<<21 | 1<<12
3983rf = c.chipfloat7(p.From.Val.(float64))
3984if rf < 0 {
3985c.ctxt.Diag("invalid floating-point immediate\n%v", p)
3986}
3987if p.As == AFMOVD {
3988o1 |= 1 << 22
3989}
3990o1 |= (uint32(rf&0xff) << 13) | uint32(p.To.Reg&31)
3991
3992case 56: /* floating point compare */
3993o1 = c.oprrr(p, p.As)
3994
3995var rf int
3996if p.From.Type == obj.TYPE_FCONST {
3997o1 |= 8 /* zero */
3998rf = 0
3999} else {
4000rf = int(p.From.Reg)
4001}
4002rt := int(p.Reg)
4003o1 |= uint32(rf&31)<<16 | uint32(rt&31)<<5
4004
4005case 57: /* floating point conditional compare */
4006o1 = c.oprrr(p, p.As)
4007
4008cond := int(p.From.Reg)
4009if cond < COND_EQ || cond > COND_NV {
4010c.ctxt.Diag("invalid condition\n%v", p)
4011} else {
4012cond -= COND_EQ
4013}
4014
4015nzcv := int(p.To.Offset)
4016if nzcv&^0xF != 0 {
4017c.ctxt.Diag("implausible condition\n%v", p)
4018}
4019rf := int(p.Reg)
4020if p.GetFrom3() == nil || p.GetFrom3().Reg < REG_F0 || p.GetFrom3().Reg > REG_F31 {
4021c.ctxt.Diag("illegal FCCMP\n%v", p)
4022break
4023}
4024rt := int(p.GetFrom3().Reg)
4025o1 |= uint32(rf&31)<<16 | uint32(cond&15)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
4026
4027case 58: /* ldar/ldarb/ldarh/ldaxp/ldxp/ldaxr/ldxr */
4028o1 = c.opload(p, p.As)
4029
4030o1 |= 0x1F << 16
4031o1 |= uint32(p.From.Reg&31) << 5
4032if p.As == ALDXP || p.As == ALDXPW || p.As == ALDAXP || p.As == ALDAXPW {
4033if int(p.To.Reg) == int(p.To.Offset) {
4034c.ctxt.Diag("constrained unpredictable behavior: %v", p)
4035}
4036o1 |= uint32(p.To.Offset&31) << 10
4037} else {
4038o1 |= 0x1F << 10
4039}
4040o1 |= uint32(p.To.Reg & 31)
4041
4042case 59: /* stxr/stlxr/stxp/stlxp */
4043s := p.RegTo2
4044n := p.To.Reg
4045t := p.From.Reg
4046if isSTLXRop(p.As) {
4047if s == t || (s == n && n != REGSP) {
4048c.ctxt.Diag("constrained unpredictable behavior: %v", p)
4049}
4050} else if isSTXPop(p.As) {
4051t2 := int16(p.From.Offset)
4052if (s == t || s == t2) || (s == n && n != REGSP) {
4053c.ctxt.Diag("constrained unpredictable behavior: %v", p)
4054}
4055}
4056if s == REG_RSP {
4057c.ctxt.Diag("illegal destination register: %v\n", p)
4058}
4059o1 = c.opstore(p, p.As)
4060
4061if p.RegTo2 != obj.REG_NONE {
4062o1 |= uint32(p.RegTo2&31) << 16
4063} else {
4064o1 |= 0x1F << 16
4065}
4066if isSTXPop(p.As) {
4067o1 |= uint32(p.From.Offset&31) << 10
4068}
4069o1 |= uint32(p.To.Reg&31)<<5 | uint32(p.From.Reg&31)
4070
4071case 60: /* adrp label,r */
4072d := c.brdist(p, 12, 21, 0)
4073
4074o1 = ADR(1, uint32(d), uint32(p.To.Reg))
4075
4076case 61: /* adr label, r */
4077d := c.brdist(p, 0, 21, 0)
4078
4079o1 = ADR(0, uint32(d), uint32(p.To.Reg))
4080
4081case 62: /* op $movcon, [R], R -> mov $movcon, REGTMP + op REGTMP, [R], R */
4082if p.Reg == REGTMP {
4083c.ctxt.Diag("cannot use REGTMP as source: %v\n", p)
4084}
4085if isADDWop(p.As) || isANDWop(p.As) {
4086o1 = c.omovconst(AMOVW, p, &p.From, REGTMP)
4087} else {
4088o1 = c.omovconst(AMOVD, p, &p.From, REGTMP)
4089}
4090
4091rt := int(p.To.Reg)
4092if p.To.Type == obj.TYPE_NONE {
4093rt = REGZERO
4094}
4095r := int(p.Reg)
4096if r == 0 {
4097r = rt
4098}
4099if p.To.Reg == REGSP || r == REGSP {
4100o2 = c.opxrrr(p, p.As, false)
4101o2 |= REGTMP & 31 << 16
4102o2 |= LSL0_64
4103} else {
4104o2 = c.oprrr(p, p.As)
4105o2 |= REGTMP & 31 << 16 /* shift is 0 */
4106}
4107o2 |= uint32(r&31) << 5
4108o2 |= uint32(rt & 31)
4109
4110/* reloc ops */
4111case 64: /* movT R,addr -> adrp + add + movT R, (REGTMP) */
4112o1 = ADR(1, 0, REGTMP)
4113o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
4114rel := obj.Addrel(c.cursym)
4115rel.Off = int32(c.pc)
4116rel.Siz = 8
4117rel.Sym = p.To.Sym
4118rel.Add = p.To.Offset
4119rel.Type = objabi.R_ADDRARM64
4120o3 = c.olsr12u(p, int32(c.opstr12(p, p.As)), 0, REGTMP, int(p.From.Reg))
4121
4122case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
4123o1 = ADR(1, 0, REGTMP)
4124o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
4125rel := obj.Addrel(c.cursym)
4126rel.Off = int32(c.pc)
4127rel.Siz = 8
4128rel.Sym = p.From.Sym
4129rel.Add = p.From.Offset
4130rel.Type = objabi.R_ADDRARM64
4131o3 = c.olsr12u(p, int32(c.opldr12(p, p.As)), 0, REGTMP, int(p.To.Reg))
4132
4133case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
4134v := int32(c.regoff(&p.From))
4135r := int(p.From.Reg)
4136if r == obj.REG_NONE {
4137r = int(o.param)
4138}
4139if r == obj.REG_NONE {
4140c.ctxt.Diag("invalid ldp source: %v\n", p)
4141}
4142o1 |= c.opldpstp(p, o, v, uint32(r), uint32(p.To.Reg), uint32(p.To.Offset), 1)
4143
4144case 67: /* stp (r1, r2), O(R)!; stp (r1, r2), (R)O! */
4145r := int(p.To.Reg)
4146if r == obj.REG_NONE {
4147r = int(o.param)
4148}
4149if r == obj.REG_NONE {
4150c.ctxt.Diag("invalid stp destination: %v\n", p)
4151}
4152v := int32(c.regoff(&p.To))
4153o1 = c.opldpstp(p, o, v, uint32(r), uint32(p.From.Reg), uint32(p.From.Offset), 0)
4154
4155case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
4156// NOTE: this case does not use REGTMP. If it ever does,
4157// remove the NOTUSETMP flag in optab.
4158if p.As == AMOVW {
4159c.ctxt.Diag("invalid load of 32-bit address: %v", p)
4160}
4161o1 = ADR(1, 0, uint32(p.To.Reg))
4162o2 = c.opirr(p, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
4163rel := obj.Addrel(c.cursym)
4164rel.Off = int32(c.pc)
4165rel.Siz = 8
4166rel.Sym = p.From.Sym
4167rel.Add = p.From.Offset
4168rel.Type = objabi.R_ADDRARM64
4169
4170case 69: /* LE model movd $tlsvar, reg -> movz reg, 0 + reloc */
4171o1 = c.opirr(p, AMOVZ)
4172o1 |= uint32(p.To.Reg & 31)
4173rel := obj.Addrel(c.cursym)
4174rel.Off = int32(c.pc)
4175rel.Siz = 4
4176rel.Sym = p.From.Sym
4177rel.Type = objabi.R_ARM64_TLS_LE
4178if p.From.Offset != 0 {
4179c.ctxt.Diag("invalid offset on MOVW $tlsvar")
4180}
4181
4182case 70: /* IE model movd $tlsvar, reg -> adrp REGTMP, 0; ldr reg, [REGTMP, #0] + relocs */
4183o1 = ADR(1, 0, REGTMP)
4184o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
4185rel := obj.Addrel(c.cursym)
4186rel.Off = int32(c.pc)
4187rel.Siz = 8
4188rel.Sym = p.From.Sym
4189rel.Add = 0
4190rel.Type = objabi.R_ARM64_TLS_IE
4191if p.From.Offset != 0 {
4192c.ctxt.Diag("invalid offset on MOVW $tlsvar")
4193}
4194
4195case 71: /* movd sym@GOT, reg -> adrp REGTMP, #0; ldr reg, [REGTMP, #0] + relocs */
4196o1 = ADR(1, 0, REGTMP)
4197o2 = c.olsr12u(p, int32(c.opldr12(p, AMOVD)), 0, REGTMP, int(p.To.Reg))
4198rel := obj.Addrel(c.cursym)
4199rel.Off = int32(c.pc)
4200rel.Siz = 8
4201rel.Sym = p.From.Sym
4202rel.Add = 0
4203rel.Type = objabi.R_ARM64_GOTPCREL
4204
4205case 72: /* vaddp/vand/vcmeq/vorr/vadd/veor/vfmla/vfmls/vbit/vbsl/vcmtst/vsub/vbif/vuzip1/vuzip2 Vm.<T>, Vn.<T>, Vd.<T> */
4206af := int((p.From.Reg >> 5) & 15)
4207af3 := int((p.Reg >> 5) & 15)
4208at := int((p.To.Reg >> 5) & 15)
4209if af != af3 || af != at {
4210c.ctxt.Diag("operand mismatch: %v", p)
4211break
4212}
4213o1 = c.oprrr(p, p.As)
4214rf := int((p.From.Reg) & 31)
4215rt := int((p.To.Reg) & 31)
4216r := int((p.Reg) & 31)
4217
4218Q := 0
4219size := 0
4220switch af {
4221case ARNG_16B:
4222Q = 1
4223size = 0
4224case ARNG_2D:
4225Q = 1
4226size = 3
4227case ARNG_2S:
4228Q = 0
4229size = 2
4230case ARNG_4H:
4231Q = 0
4232size = 1
4233case ARNG_4S:
4234Q = 1
4235size = 2
4236case ARNG_8B:
4237Q = 0
4238size = 0
4239case ARNG_8H:
4240Q = 1
4241size = 1
4242default:
4243c.ctxt.Diag("invalid arrangement: %v", p)
4244}
4245
4246switch p.As {
4247case AVORR, AVAND, AVEOR, AVBIT, AVBSL, AVBIF:
4248if af != ARNG_16B && af != ARNG_8B {
4249c.ctxt.Diag("invalid arrangement: %v", p)
4250}
4251case AVFMLA, AVFMLS:
4252if af != ARNG_2D && af != ARNG_2S && af != ARNG_4S {
4253c.ctxt.Diag("invalid arrangement: %v", p)
4254}
4255}
4256switch p.As {
4257case AVAND, AVEOR:
4258size = 0
4259case AVBSL:
4260size = 1
4261case AVORR, AVBIT, AVBIF:
4262size = 2
4263case AVFMLA, AVFMLS:
4264if af == ARNG_2D {
4265size = 1
4266} else {
4267size = 0
4268}
4269}
4270
4271o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
4272
4273case 73: /* vmov V.<T>[index], R */
4274rf := int(p.From.Reg)
4275rt := int(p.To.Reg)
4276imm5 := 0
4277o1 = 7<<25 | 0xf<<10
4278index := int(p.From.Index)
4279switch (p.From.Reg >> 5) & 15 {
4280case ARNG_B:
4281c.checkindex(p, index, 15)
4282imm5 |= 1
4283imm5 |= index << 1
4284case ARNG_H:
4285c.checkindex(p, index, 7)
4286imm5 |= 2
4287imm5 |= index << 2
4288case ARNG_S:
4289c.checkindex(p, index, 3)
4290imm5 |= 4
4291imm5 |= index << 3
4292case ARNG_D:
4293c.checkindex(p, index, 1)
4294imm5 |= 8
4295imm5 |= index << 4
4296o1 |= 1 << 30
4297default:
4298c.ctxt.Diag("invalid arrangement: %v", p)
4299}
4300o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
4301
4302case 74:
4303// add $O, R, Rtmp or sub $O, R, Rtmp
4304// ldp (Rtmp), (R1, R2)
4305r := int(p.From.Reg)
4306if r == obj.REG_NONE {
4307r = int(o.param)
4308}
4309if r == obj.REG_NONE {
4310c.ctxt.Diag("invalid ldp source: %v", p)
4311}
4312v := int32(c.regoff(&p.From))
4313
4314if v > 0 {
4315if v > 4095 {
4316c.ctxt.Diag("offset out of range: %v", p)
4317}
4318o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
4319}
4320if v < 0 {
4321if v < -4095 {
4322c.ctxt.Diag("offset out of range: %v", p)
4323}
4324o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
4325}
4326o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
4327
4328case 75:
4329// mov $L, Rtmp (from constant pool)
4330// add Rtmp, R, Rtmp
4331// ldp (Rtmp), (R1, R2)
4332r := int(p.From.Reg)
4333if r == obj.REG_NONE {
4334r = int(o.param)
4335}
4336if r == obj.REG_NONE {
4337c.ctxt.Diag("invalid ldp source: %v", p)
4338}
4339o1 = c.omovlit(AMOVD, p, &p.From, REGTMP)
4340o2 = c.opxrrr(p, AADD, false)
4341o2 |= (REGTMP & 31) << 16
4342o2 |= uint32(r&31) << 5
4343o2 |= uint32(REGTMP & 31)
4344o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
4345
4346case 76:
4347// add $O, R, Rtmp or sub $O, R, Rtmp
4348// stp (R1, R2), (Rtmp)
4349r := int(p.To.Reg)
4350if r == obj.REG_NONE {
4351r = int(o.param)
4352}
4353if r == obj.REG_NONE {
4354c.ctxt.Diag("invalid stp destination: %v", p)
4355}
4356v := int32(c.regoff(&p.To))
4357if v > 0 {
4358if v > 4095 {
4359c.ctxt.Diag("offset out of range: %v", p)
4360}
4361o1 = c.oaddi(p, int32(c.opirr(p, AADD)), v, r, REGTMP)
4362}
4363if v < 0 {
4364if v < -4095 {
4365c.ctxt.Diag("offset out of range: %v", p)
4366}
4367o1 = c.oaddi(p, int32(c.opirr(p, ASUB)), -v, r, REGTMP)
4368}
4369o2 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
4370
4371case 77:
4372// mov $L, Rtmp (from constant pool)
4373// add Rtmp, R, Rtmp
4374// stp (R1, R2), (Rtmp)
4375r := int(p.To.Reg)
4376if r == obj.REG_NONE {
4377r = int(o.param)
4378}
4379if r == obj.REG_NONE {
4380c.ctxt.Diag("invalid stp destination: %v", p)
4381}
4382o1 = c.omovlit(AMOVD, p, &p.To, REGTMP)
4383o2 = c.opxrrr(p, AADD, false)
4384o2 |= REGTMP & 31 << 16
4385o2 |= uint32(r&31) << 5
4386o2 |= uint32(REGTMP & 31)
4387o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
4388
4389case 78: /* vmov R, V.<T>[index] */
4390rf := int(p.From.Reg)
4391rt := int(p.To.Reg)
4392imm5 := 0
4393o1 = 1<<30 | 7<<25 | 7<<10
4394index := int(p.To.Index)
4395switch (p.To.Reg >> 5) & 15 {
4396case ARNG_B:
4397c.checkindex(p, index, 15)
4398imm5 |= 1
4399imm5 |= index << 1
4400case ARNG_H:
4401c.checkindex(p, index, 7)
4402imm5 |= 2
4403imm5 |= index << 2
4404case ARNG_S:
4405c.checkindex(p, index, 3)
4406imm5 |= 4
4407imm5 |= index << 3
4408case ARNG_D:
4409c.checkindex(p, index, 1)
4410imm5 |= 8
4411imm5 |= index << 4
4412default:
4413c.ctxt.Diag("invalid arrangement: %v", p)
4414}
4415o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
4416
4417case 79: /* vdup Vn.<T>[index], Vd.<T> */
4418rf := int(p.From.Reg)
4419rt := int(p.To.Reg)
4420o1 = 7<<25 | 1<<10
4421var imm5, Q int
4422index := int(p.From.Index)
4423switch (p.To.Reg >> 5) & 15 {
4424case ARNG_16B:
4425c.checkindex(p, index, 15)
4426Q = 1
4427imm5 = 1
4428imm5 |= index << 1
4429case ARNG_2D:
4430c.checkindex(p, index, 1)
4431Q = 1
4432imm5 = 8
4433imm5 |= index << 4
4434case ARNG_2S:
4435c.checkindex(p, index, 3)
4436Q = 0
4437imm5 = 4
4438imm5 |= index << 3
4439case ARNG_4H:
4440c.checkindex(p, index, 7)
4441Q = 0
4442imm5 = 2
4443imm5 |= index << 2
4444case ARNG_4S:
4445c.checkindex(p, index, 3)
4446Q = 1
4447imm5 = 4
4448imm5 |= index << 3
4449case ARNG_8B:
4450c.checkindex(p, index, 15)
4451Q = 0
4452imm5 = 1
4453imm5 |= index << 1
4454case ARNG_8H:
4455c.checkindex(p, index, 7)
4456Q = 1
4457imm5 = 2
4458imm5 |= index << 2
4459default:
4460c.ctxt.Diag("invalid arrangement: %v", p)
4461}
4462o1 |= (uint32(Q&1) << 30) | (uint32(imm5&0x1f) << 16)
4463o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
4464
4465case 80: /* vmov V.<T>[index], Vn */
4466rf := int(p.From.Reg)
4467rt := int(p.To.Reg)
4468imm5 := 0
4469index := int(p.From.Index)
4470switch p.As {
4471case AVMOV:
4472o1 = 1<<30 | 15<<25 | 1<<10
4473switch (p.From.Reg >> 5) & 15 {
4474case ARNG_B:
4475c.checkindex(p, index, 15)
4476imm5 |= 1
4477imm5 |= index << 1
4478case ARNG_H:
4479c.checkindex(p, index, 7)
4480imm5 |= 2
4481imm5 |= index << 2
4482case ARNG_S:
4483c.checkindex(p, index, 3)
4484imm5 |= 4
4485imm5 |= index << 3
4486case ARNG_D:
4487c.checkindex(p, index, 1)
4488imm5 |= 8
4489imm5 |= index << 4
4490default:
4491c.ctxt.Diag("invalid arrangement: %v", p)
4492}
4493default:
4494c.ctxt.Diag("unsupported op %v", p.As)
4495}
4496o1 |= (uint32(imm5&0x1f) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
4497
4498case 81: /* vld[1-4]|vld[1-4]r (Rn), [Vt1.<T>, Vt2.<T>, ...] */
4499c.checkoffset(p, p.As)
4500r := int(p.From.Reg)
4501o1 = c.oprrr(p, p.As)
4502if o.scond == C_XPOST {
4503o1 |= 1 << 23
4504if p.From.Index == 0 {
4505// immediate offset variant
4506o1 |= 0x1f << 16
4507} else {
4508// register offset variant
4509if isRegShiftOrExt(&p.From) {
4510c.ctxt.Diag("invalid extended register op: %v\n", p)
4511}
4512o1 |= uint32(p.From.Index&0x1f) << 16
4513}
4514}
4515o1 |= uint32(p.To.Offset)
4516// cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset
4517// add opcode(bit 12-15) for vld1, mask it off if it's not vld1
4518o1 = c.maskOpvldvst(p, o1)
4519o1 |= uint32(r&31) << 5
4520
4521case 82: /* vmov Rn, Vd.<T> */
4522rf := int(p.From.Reg)
4523rt := int(p.To.Reg)
4524o1 = 7<<25 | 3<<10
4525var imm5, Q uint32
4526switch (p.To.Reg >> 5) & 15 {
4527case ARNG_16B:
4528Q = 1
4529imm5 = 1
4530case ARNG_2D:
4531Q = 1
4532imm5 = 8
4533case ARNG_2S:
4534Q = 0
4535imm5 = 4
4536case ARNG_4H:
4537Q = 0
4538imm5 = 2
4539case ARNG_4S:
4540Q = 1
4541imm5 = 4
4542case ARNG_8B:
4543Q = 0
4544imm5 = 1
4545case ARNG_8H:
4546Q = 1
4547imm5 = 2
4548default:
4549c.ctxt.Diag("invalid arrangement on VMOV Rn, Vd.<T>: %v\n", p)
4550}
4551o1 |= (Q & 1 << 30) | (imm5 & 0x1f << 16)
4552o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
4553
4554case 83: /* vmov Vn.<T>, Vd.<T> */
4555af := int((p.From.Reg >> 5) & 15)
4556at := int((p.To.Reg >> 5) & 15)
4557if af != at {
4558c.ctxt.Diag("invalid arrangement: %v\n", p)
4559}
4560o1 = c.oprrr(p, p.As)
4561rf := int((p.From.Reg) & 31)
4562rt := int((p.To.Reg) & 31)
4563
4564var Q, size uint32
4565switch af {
4566case ARNG_8B:
4567Q = 0
4568size = 0
4569case ARNG_16B:
4570Q = 1
4571size = 0
4572case ARNG_4H:
4573Q = 0
4574size = 1
4575case ARNG_8H:
4576Q = 1
4577size = 1
4578case ARNG_2S:
4579Q = 0
4580size = 2
4581case ARNG_4S:
4582Q = 1
4583size = 2
4584default:
4585c.ctxt.Diag("invalid arrangement: %v\n", p)
4586}
4587
4588if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) {
4589c.ctxt.Diag("invalid arrangement: %v", p)
4590}
4591
4592if p.As == AVREV32 && (af == ARNG_2S || af == ARNG_4S) {
4593c.ctxt.Diag("invalid arrangement: %v", p)
4594}
4595
4596if p.As == AVREV16 && af != ARNG_8B && af != ARNG_16B {
4597c.ctxt.Diag("invalid arrangement: %v", p)
4598}
4599
4600if p.As == AVMOV {
4601o1 |= uint32(rf&31) << 16
4602}
4603
4604if p.As == AVRBIT {
4605size = 1
4606}
4607
4608o1 |= (Q&1)<<30 | (size&3)<<22 | uint32(rf&31)<<5 | uint32(rt&31)
4609
4610case 84: /* vst[1-4] [Vt1.<T>, Vt2.<T>, ...], (Rn) */
4611c.checkoffset(p, p.As)
4612r := int(p.To.Reg)
4613o1 = 3 << 26
4614if o.scond == C_XPOST {
4615o1 |= 1 << 23
4616if p.To.Index == 0 {
4617// immediate offset variant
4618o1 |= 0x1f << 16
4619} else {
4620// register offset variant
4621if isRegShiftOrExt(&p.To) {
4622c.ctxt.Diag("invalid extended register: %v\n", p)
4623}
4624o1 |= uint32(p.To.Index&31) << 16
4625}
4626}
4627o1 |= uint32(p.From.Offset)
4628// cmd/asm/internal/arch/arm64.go:ARM64RegisterListOffset
4629// add opcode(bit 12-15) for vst1, mask it off if it's not vst1
4630o1 = c.maskOpvldvst(p, o1)
4631o1 |= uint32(r&31) << 5
4632
4633case 85: /* vaddv/vuaddlv Vn.<T>, Vd*/
4634af := int((p.From.Reg >> 5) & 15)
4635o1 = c.oprrr(p, p.As)
4636rf := int((p.From.Reg) & 31)
4637rt := int((p.To.Reg) & 31)
4638Q := 0
4639size := 0
4640switch af {
4641case ARNG_8B:
4642Q = 0
4643size = 0
4644case ARNG_16B:
4645Q = 1
4646size = 0
4647case ARNG_4H:
4648Q = 0
4649size = 1
4650case ARNG_8H:
4651Q = 1
4652size = 1
4653case ARNG_4S:
4654Q = 1
4655size = 2
4656default:
4657c.ctxt.Diag("invalid arrangement: %v\n", p)
4658}
4659o1 |= (uint32(Q&1) << 30) | (uint32(size&3) << 22) | (uint32(rf&31) << 5) | uint32(rt&31)
4660
4661case 86: /* vmovi $imm8, Vd.<T>*/
4662at := int((p.To.Reg >> 5) & 15)
4663r := int(p.From.Offset)
4664if r > 255 || r < 0 {
4665c.ctxt.Diag("immediate constant out of range: %v\n", p)
4666}
4667rt := int((p.To.Reg) & 31)
4668Q := 0
4669switch at {
4670case ARNG_8B:
4671Q = 0
4672case ARNG_16B:
4673Q = 1
4674default:
4675c.ctxt.Diag("invalid arrangement: %v\n", p)
4676}
4677o1 = 0xf<<24 | 0xe<<12 | 1<<10
4678o1 |= (uint32(Q&1) << 30) | (uint32((r>>5)&7) << 16) | (uint32(r&0x1f) << 5) | uint32(rt&31)
4679
4680case 87: /* stp (r,r), addr(SB) -> adrp + add + stp */
4681o1 = ADR(1, 0, REGTMP)
4682o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
4683rel := obj.Addrel(c.cursym)
4684rel.Off = int32(c.pc)
4685rel.Siz = 8
4686rel.Sym = p.To.Sym
4687rel.Add = p.To.Offset
4688rel.Type = objabi.R_ADDRARM64
4689o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.From.Reg), uint32(p.From.Offset), 0)
4690
4691case 88: /* ldp addr(SB), (r,r) -> adrp + add + ldp */
4692o1 = ADR(1, 0, REGTMP)
4693o2 = c.opirr(p, AADD) | REGTMP&31<<5 | REGTMP&31
4694rel := obj.Addrel(c.cursym)
4695rel.Off = int32(c.pc)
4696rel.Siz = 8
4697rel.Sym = p.From.Sym
4698rel.Add = p.From.Offset
4699rel.Type = objabi.R_ADDRARM64
4700o3 |= c.opldpstp(p, o, 0, uint32(REGTMP), uint32(p.To.Reg), uint32(p.To.Offset), 1)
4701
4702case 89: /* vadd/vsub Vm, Vn, Vd */
4703switch p.As {
4704case AVADD:
4705o1 = 5<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10
4706
4707case AVSUB:
4708o1 = 7<<28 | 7<<25 | 7<<21 | 1<<15 | 1<<10
4709
4710default:
4711c.ctxt.Diag("bad opcode: %v\n", p)
4712break
4713}
4714
4715rf := int(p.From.Reg)
4716rt := int(p.To.Reg)
4717r := int(p.Reg)
4718if r == 0 {
4719r = rt
4720}
4721o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
4722
4723// This is supposed to be something that stops execution.
4724// It's not supposed to be reached, ever, but if it is, we'd
4725// like to be able to tell how we got there. Assemble as
4726// 0xbea71700 which is guaranteed to raise undefined instruction
4727// exception.
4728case 90:
4729o1 = 0xbea71700
4730
4731case 91: /* prfm imm(Rn), <prfop | $imm5> */
4732imm := uint32(p.From.Offset)
4733r := p.From.Reg
4734v := uint32(0xff)
4735if p.To.Type == obj.TYPE_CONST {
4736v = uint32(p.To.Offset)
4737if v > 31 {
4738c.ctxt.Diag("illegal prefetch operation\n%v", p)
4739}
4740} else {
4741for i := 0; i < len(prfopfield); i++ {
4742if prfopfield[i].reg == p.To.Reg {
4743v = prfopfield[i].enc
4744break
4745}
4746}
4747if v == 0xff {
4748c.ctxt.Diag("illegal prefetch operation:\n%v", p)
4749}
4750}
4751
4752o1 = c.opldrpp(p, p.As)
4753o1 |= (uint32(r&31) << 5) | (uint32((imm>>3)&0xfff) << 10) | (uint32(v & 31))
4754
4755case 92: /* vmov Vn.<T>[index], Vd.<T>[index] */
4756rf := int(p.From.Reg)
4757rt := int(p.To.Reg)
4758imm4 := 0
4759imm5 := 0
4760o1 = 3<<29 | 7<<25 | 1<<10
4761index1 := int(p.To.Index)
4762index2 := int(p.From.Index)
4763if ((p.To.Reg >> 5) & 15) != ((p.From.Reg >> 5) & 15) {
4764c.ctxt.Diag("operand mismatch: %v", p)
4765}
4766switch (p.To.Reg >> 5) & 15 {
4767case ARNG_B:
4768c.checkindex(p, index1, 15)
4769c.checkindex(p, index2, 15)
4770imm5 |= 1
4771imm5 |= index1 << 1
4772imm4 |= index2
4773case ARNG_H:
4774c.checkindex(p, index1, 7)
4775c.checkindex(p, index2, 7)
4776imm5 |= 2
4777imm5 |= index1 << 2
4778imm4 |= index2 << 1
4779case ARNG_S:
4780c.checkindex(p, index1, 3)
4781c.checkindex(p, index2, 3)
4782imm5 |= 4
4783imm5 |= index1 << 3
4784imm4 |= index2 << 2
4785case ARNG_D:
4786c.checkindex(p, index1, 1)
4787c.checkindex(p, index2, 1)
4788imm5 |= 8
4789imm5 |= index1 << 4
4790imm4 |= index2 << 3
4791default:
4792c.ctxt.Diag("invalid arrangement: %v", p)
4793}
4794o1 |= (uint32(imm5&0x1f) << 16) | (uint32(imm4&0xf) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
4795
4796case 93: /* vpmull{2} Vm.<T>, Vn.<T>, Vd */
4797af := int((p.From.Reg >> 5) & 15)
4798at := int((p.To.Reg >> 5) & 15)
4799a := int((p.Reg >> 5) & 15)
4800
4801var Q, size uint32
4802if p.As == AVPMULL {
4803Q = 0
4804} else {
4805Q = 1
4806}
4807
4808var fArng int
4809switch at {
4810case ARNG_8H:
4811if Q == 0 {
4812fArng = ARNG_8B
4813} else {
4814fArng = ARNG_16B
4815}
4816size = 0
4817case ARNG_1Q:
4818if Q == 0 {
4819fArng = ARNG_1D
4820} else {
4821fArng = ARNG_2D
4822}
4823size = 3
4824default:
4825c.ctxt.Diag("invalid arrangement on Vd.<T>: %v", p)
4826}
4827
4828if af != a || af != fArng {
4829c.ctxt.Diag("invalid arrangement: %v", p)
4830}
4831
4832o1 = c.oprrr(p, p.As)
4833rf := int((p.From.Reg) & 31)
4834rt := int((p.To.Reg) & 31)
4835r := int((p.Reg) & 31)
4836
4837o1 |= ((Q & 1) << 30) | ((size & 3) << 22) | (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
4838
4839case 94: /* vext $imm4, Vm.<T>, Vn.<T>, Vd.<T> */
4840af := int(((p.GetFrom3().Reg) >> 5) & 15)
4841at := int((p.To.Reg >> 5) & 15)
4842a := int((p.Reg >> 5) & 15)
4843index := int(p.From.Offset)
4844
4845if af != a || af != at {
4846c.ctxt.Diag("invalid arrangement: %v", p)
4847break
4848}
4849
4850var Q uint32
4851var b int
4852if af == ARNG_8B {
4853Q = 0
4854b = 7
4855} else if af == ARNG_16B {
4856Q = 1
4857b = 15
4858} else {
4859c.ctxt.Diag("invalid arrangement, should be B8 or B16: %v", p)
4860break
4861}
4862
4863if index < 0 || index > b {
4864c.ctxt.Diag("illegal offset: %v", p)
4865}
4866
4867o1 = c.opirr(p, p.As)
4868rf := int((p.GetFrom3().Reg) & 31)
4869rt := int((p.To.Reg) & 31)
4870r := int((p.Reg) & 31)
4871
4872o1 |= ((Q & 1) << 30) | (uint32(r&31) << 16) | (uint32(index&15) << 11) | (uint32(rf&31) << 5) | uint32(rt&31)
4873
4874case 95: /* vushr $shift, Vn.<T>, Vd.<T> */
4875at := int((p.To.Reg >> 5) & 15)
4876af := int((p.Reg >> 5) & 15)
4877shift := int(p.From.Offset)
4878
4879if af != at {
4880c.ctxt.Diag("invalid arrangement on op Vn.<T>, Vd.<T>: %v", p)
4881}
4882
4883var Q uint32
4884var imax, esize int
4885
4886switch af {
4887case ARNG_8B, ARNG_4H, ARNG_2S:
4888Q = 0
4889case ARNG_16B, ARNG_8H, ARNG_4S, ARNG_2D:
4890Q = 1
4891default:
4892c.ctxt.Diag("invalid arrangement on op Vn.<T>, Vd.<T>: %v", p)
4893}
4894
4895switch af {
4896case ARNG_8B, ARNG_16B:
4897imax = 15
4898esize = 8
4899case ARNG_4H, ARNG_8H:
4900imax = 31
4901esize = 16
4902case ARNG_2S, ARNG_4S:
4903imax = 63
4904esize = 32
4905case ARNG_2D:
4906imax = 127
4907esize = 64
4908}
4909
4910imm := 0
4911
4912switch p.As {
4913case AVUSHR, AVSRI:
4914imm = esize*2 - shift
4915if imm < esize || imm > imax {
4916c.ctxt.Diag("shift out of range: %v", p)
4917}
4918case AVSHL:
4919imm = esize + shift
4920if imm > imax {
4921c.ctxt.Diag("shift out of range: %v", p)
4922}
4923default:
4924c.ctxt.Diag("invalid instruction %v\n", p)
4925}
4926
4927o1 = c.opirr(p, p.As)
4928rt := int((p.To.Reg) & 31)
4929rf := int((p.Reg) & 31)
4930
4931o1 |= ((Q & 1) << 30) | (uint32(imm&127) << 16) | (uint32(rf&31) << 5) | uint32(rt&31)
4932
4933case 96: /* vst1 Vt1.<T>[index], offset(Rn) */
4934af := int((p.From.Reg >> 5) & 15)
4935rt := int((p.From.Reg) & 31)
4936rf := int((p.To.Reg) & 31)
4937r := int(p.To.Index & 31)
4938index := int(p.From.Index)
4939offset := int32(c.regoff(&p.To))
4940
4941if o.scond == C_XPOST {
4942if (p.To.Index != 0) && (offset != 0) {
4943c.ctxt.Diag("invalid offset: %v", p)
4944}
4945if p.To.Index == 0 && offset == 0 {
4946c.ctxt.Diag("invalid offset: %v", p)
4947}
4948}
4949
4950if offset != 0 {
4951r = 31
4952}
4953
4954var Q, S, size int
4955var opcode uint32
4956switch af {
4957case ARNG_B:
4958c.checkindex(p, index, 15)
4959if o.scond == C_XPOST && offset != 0 && offset != 1 {
4960c.ctxt.Diag("invalid offset: %v", p)
4961}
4962Q = index >> 3
4963S = (index >> 2) & 1
4964size = index & 3
4965opcode = 0
4966case ARNG_H:
4967c.checkindex(p, index, 7)
4968if o.scond == C_XPOST && offset != 0 && offset != 2 {
4969c.ctxt.Diag("invalid offset: %v", p)
4970}
4971Q = index >> 2
4972S = (index >> 1) & 1
4973size = (index & 1) << 1
4974opcode = 2
4975case ARNG_S:
4976c.checkindex(p, index, 3)
4977if o.scond == C_XPOST && offset != 0 && offset != 4 {
4978c.ctxt.Diag("invalid offset: %v", p)
4979}
4980Q = index >> 1
4981S = index & 1
4982size = 0
4983opcode = 4
4984case ARNG_D:
4985c.checkindex(p, index, 1)
4986if o.scond == C_XPOST && offset != 0 && offset != 8 {
4987c.ctxt.Diag("invalid offset: %v", p)
4988}
4989Q = index
4990S = 0
4991size = 1
4992opcode = 4
4993default:
4994c.ctxt.Diag("invalid arrangement: %v", p)
4995}
4996
4997if o.scond == C_XPOST {
4998o1 |= 27 << 23
4999} else {
5000o1 |= 26 << 23
5001}
5002
5003o1 |= (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)
5004
5005case 97: /* vld1 offset(Rn), vt.<T>[index] */
5006at := int((p.To.Reg >> 5) & 15)
5007rt := int((p.To.Reg) & 31)
5008rf := int((p.From.Reg) & 31)
5009r := int(p.From.Index & 31)
5010index := int(p.To.Index)
5011offset := int32(c.regoff(&p.From))
5012
5013if o.scond == C_XPOST {
5014if (p.From.Index != 0) && (offset != 0) {
5015c.ctxt.Diag("invalid offset: %v", p)
5016}
5017if p.From.Index == 0 && offset == 0 {
5018c.ctxt.Diag("invalid offset: %v", p)
5019}
5020}
5021
5022if offset != 0 {
5023r = 31
5024}
5025
5026Q := 0
5027S := 0
5028size := 0
5029var opcode uint32
5030switch at {
5031case ARNG_B:
5032c.checkindex(p, index, 15)
5033if o.scond == C_XPOST && offset != 0 && offset != 1 {
5034c.ctxt.Diag("invalid offset: %v", p)
5035}
5036Q = index >> 3
5037S = (index >> 2) & 1
5038size = index & 3
5039opcode = 0
5040case ARNG_H:
5041c.checkindex(p, index, 7)
5042if o.scond == C_XPOST && offset != 0 && offset != 2 {
5043c.ctxt.Diag("invalid offset: %v", p)
5044}
5045Q = index >> 2
5046S = (index >> 1) & 1
5047size = (index & 1) << 1
5048opcode = 2
5049case ARNG_S:
5050c.checkindex(p, index, 3)
5051if o.scond == C_XPOST && offset != 0 && offset != 4 {
5052c.ctxt.Diag("invalid offset: %v", p)
5053}
5054Q = index >> 1
5055S = index & 1
5056size = 0
5057opcode = 4
5058case ARNG_D:
5059c.checkindex(p, index, 1)
5060if o.scond == C_XPOST && offset != 0 && offset != 8 {
5061c.ctxt.Diag("invalid offset: %v", p)
5062}
5063Q = index
5064S = 0
5065size = 1
5066opcode = 4
5067default:
5068c.ctxt.Diag("invalid arrangement: %v", p)
5069}
5070
5071if o.scond == C_XPOST {
5072o1 |= 110 << 21
5073} else {
5074o1 |= 106 << 21
5075}
5076
5077o1 |= (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)
5078
5079case 98: /* MOVD (Rn)(Rm.SXTW[<<amount]),Rd */
5080if isRegShiftOrExt(&p.From) {
5081// extended or shifted offset register.
5082c.checkShiftAmount(p, &p.From)
5083
5084o1 = c.opldrr(p, p.As, true)
5085o1 |= c.encRegShiftOrExt(&p.From, p.From.Index) /* includes reg, op, etc */
5086} else {
5087// (Rn)(Rm), no extension or shift.
5088o1 = c.opldrr(p, p.As, false)
5089o1 |= uint32(p.From.Index&31) << 16
5090}
5091o1 |= uint32(p.From.Reg&31) << 5
5092rt := int(p.To.Reg)
5093o1 |= uint32(rt & 31)
5094
5095case 99: /* MOVD Rt, (Rn)(Rm.SXTW[<<amount]) */
5096if isRegShiftOrExt(&p.To) {
5097// extended or shifted offset register.
5098c.checkShiftAmount(p, &p.To)
5099
5100o1 = c.opstrr(p, p.As, true)
5101o1 |= c.encRegShiftOrExt(&p.To, p.To.Index) /* includes reg, op, etc */
5102} else {
5103// (Rn)(Rm), no extension or shift.
5104o1 = c.opstrr(p, p.As, false)
5105o1 |= uint32(p.To.Index&31) << 16
5106}
5107o1 |= uint32(p.To.Reg&31) << 5
5108rf := int(p.From.Reg)
5109o1 |= uint32(rf & 31)
5110
5111case 100: /* VTBL Vn.<T>, [Vt1.<T>, Vt2.<T>, ...], Vd.<T> */
5112af := int((p.From.Reg >> 5) & 15)
5113at := int((p.To.Reg >> 5) & 15)
5114if af != at {
5115c.ctxt.Diag("invalid arrangement: %v\n", p)
5116}
5117var q, len uint32
5118switch af {
5119case ARNG_8B:
5120q = 0
5121case ARNG_16B:
5122q = 1
5123default:
5124c.ctxt.Diag("invalid arrangement: %v", p)
5125}
5126rf := int(p.From.Reg)
5127rt := int(p.To.Reg)
5128offset := int(p.GetFrom3().Offset)
5129opcode := (offset >> 12) & 15
5130switch opcode {
5131case 0x7:
5132len = 0 // one register
5133case 0xa:
5134len = 1 // two register
5135case 0x6:
5136len = 2 // three registers
5137case 0x2:
5138len = 3 // four registers
5139default:
5140c.ctxt.Diag("invalid register numbers in ARM64 register list: %v", p)
5141}
5142o1 = q<<30 | 0xe<<24 | len<<13
5143o1 |= (uint32(rf&31) << 16) | uint32(offset&31)<<5 | uint32(rt&31)
5144
5145case 101: // FOMVQ/FMOVD $vcon, Vd -> load from constant pool.
5146o1 = c.omovlit(p.As, p, &p.From, int(p.To.Reg))
5147
5148case 102: /* vushll, vushll2, vuxtl, vuxtl2 */
5149o1 = c.opirr(p, p.As)
5150rf := p.Reg
5151af := uint8((p.Reg >> 5) & 15)
5152at := uint8((p.To.Reg >> 5) & 15)
5153shift := int(p.From.Offset)
5154if p.As == AVUXTL || p.As == AVUXTL2 {
5155rf = p.From.Reg
5156af = uint8((p.From.Reg >> 5) & 15)
5157shift = 0
5158}
5159
5160pack := func(q, x, y uint8) uint32 {
5161return uint32(q)<<16 | uint32(x)<<8 | uint32(y)
5162}
5163
5164var Q uint8 = uint8(o1>>30) & 1
5165var immh, width uint8
5166switch pack(Q, af, at) {
5167case pack(0, ARNG_8B, ARNG_8H):
5168immh, width = 1, 8
5169case pack(1, ARNG_16B, ARNG_8H):
5170immh, width = 1, 8
5171case pack(0, ARNG_4H, ARNG_4S):
5172immh, width = 2, 16
5173case pack(1, ARNG_8H, ARNG_4S):
5174immh, width = 2, 16
5175case pack(0, ARNG_2S, ARNG_2D):
5176immh, width = 4, 32
5177case pack(1, ARNG_4S, ARNG_2D):
5178immh, width = 4, 32
5179default:
5180c.ctxt.Diag("operand mismatch: %v\n", p)
5181}
5182if !(0 <= shift && shift <= int(width-1)) {
5183c.ctxt.Diag("shift amount out of range: %v\n", p)
5184}
5185o1 |= uint32(immh)<<19 | uint32(shift)<<16 | uint32(rf&31)<<5 | uint32(p.To.Reg&31)
5186}
5187out[0] = o1
5188out[1] = o2
5189out[2] = o3
5190out[3] = o4
5191out[4] = o5
5192}
5193
5194/*
5195* basic Rm op Rn -> Rd (using shifted register with 0)
5196* also op Rn -> Rt
5197* also Rm*Rn op Ra -> Rd
5198* also Vm op Vn -> Vd
5199*/
5200func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 {
5201switch a {
5202case AADC:
5203return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
5204
5205case AADCW:
5206return S32 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
5207
5208case AADCS:
5209return S64 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10
5210
5211case AADCSW:
5212return S32 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10
5213
5214case ANGC, ASBC:
5215return S64 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10
5216
5217case ANGCS, ASBCS:
5218return S64 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10
5219
5220case ANGCW, ASBCW:
5221return S32 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10
5222
5223case ANGCSW, ASBCSW:
5224return S32 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10
5225
5226case AADD:
5227return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5228
5229case AADDW:
5230return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5231
5232case ACMN, AADDS:
5233return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5234
5235case ACMNW, AADDSW:
5236return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5237
5238case ASUB:
5239return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5240
5241case ASUBW:
5242return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5243
5244case ACMP, ASUBS:
5245return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5246
5247case ACMPW, ASUBSW:
5248return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
5249
5250case AAND:
5251return S64 | 0<<29 | 0xA<<24
5252
5253case AANDW:
5254return S32 | 0<<29 | 0xA<<24
5255
5256case AMOVD, AORR:
5257return S64 | 1<<29 | 0xA<<24
5258
5259// case AMOVW:
5260case AMOVWU, AORRW:
5261return S32 | 1<<29 | 0xA<<24
5262
5263case AEOR:
5264return S64 | 2<<29 | 0xA<<24
5265
5266case AEORW:
5267return S32 | 2<<29 | 0xA<<24
5268
5269case AANDS, ATST:
5270return S64 | 3<<29 | 0xA<<24
5271
5272case AANDSW, ATSTW:
5273return S32 | 3<<29 | 0xA<<24
5274
5275case ABIC:
5276return S64 | 0<<29 | 0xA<<24 | 1<<21
5277
5278case ABICW:
5279return S32 | 0<<29 | 0xA<<24 | 1<<21
5280
5281case ABICS:
5282return S64 | 3<<29 | 0xA<<24 | 1<<21
5283
5284case ABICSW:
5285return S32 | 3<<29 | 0xA<<24 | 1<<21
5286
5287case AEON:
5288return S64 | 2<<29 | 0xA<<24 | 1<<21
5289
5290case AEONW:
5291return S32 | 2<<29 | 0xA<<24 | 1<<21
5292
5293case AMVN, AORN:
5294return S64 | 1<<29 | 0xA<<24 | 1<<21
5295
5296case AMVNW, AORNW:
5297return S32 | 1<<29 | 0xA<<24 | 1<<21
5298
5299case AASR:
5300return S64 | OPDP2(10) /* also ASRV */
5301
5302case AASRW:
5303return S32 | OPDP2(10)
5304
5305case ALSL:
5306return S64 | OPDP2(8)
5307
5308case ALSLW:
5309return S32 | OPDP2(8)
5310
5311case ALSR:
5312return S64 | OPDP2(9)
5313
5314case ALSRW:
5315return S32 | OPDP2(9)
5316
5317case AROR:
5318return S64 | OPDP2(11)
5319
5320case ARORW:
5321return S32 | OPDP2(11)
5322
5323case ACCMN:
5324return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* cond<<12 | nzcv<<0 */
5325
5326case ACCMNW:
5327return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4
5328
5329case ACCMP:
5330return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
5331
5332case ACCMPW:
5333return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4
5334
5335case ACRC32B:
5336return S32 | OPDP2(16)
5337
5338case ACRC32H:
5339return S32 | OPDP2(17)
5340
5341case ACRC32W:
5342return S32 | OPDP2(18)
5343
5344case ACRC32X:
5345return S64 | OPDP2(19)
5346
5347case ACRC32CB:
5348return S32 | OPDP2(20)
5349
5350case ACRC32CH:
5351return S32 | OPDP2(21)
5352
5353case ACRC32CW:
5354return S32 | OPDP2(22)
5355
5356case ACRC32CX:
5357return S64 | OPDP2(23)
5358
5359case ACSEL:
5360return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5361
5362case ACSELW:
5363return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5364
5365case ACSET:
5366return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5367
5368case ACSETW:
5369return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5370
5371case ACSETM:
5372return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5373
5374case ACSETMW:
5375return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5376
5377case ACINC, ACSINC:
5378return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5379
5380case ACINCW, ACSINCW:
5381return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5382
5383case ACINV, ACSINV:
5384return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5385
5386case ACINVW, ACSINVW:
5387return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
5388
5389case ACNEG, ACSNEG:
5390return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5391
5392case ACNEGW, ACSNEGW:
5393return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
5394
5395case AMUL, AMADD:
5396return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15
5397
5398case AMULW, AMADDW:
5399return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15
5400
5401case AMNEG, AMSUB:
5402return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15
5403
5404case AMNEGW, AMSUBW:
5405return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15
5406
5407case AMRS:
5408return SYSOP(1, 2, 0, 0, 0, 0, 0)
5409
5410case AMSR:
5411return SYSOP(0, 2, 0, 0, 0, 0, 0)
5412
5413case ANEG:
5414return S64 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21
5415
5416case ANEGW:
5417return S32 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21
5418
5419case ANEGS:
5420return S64 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21
5421
5422case ANEGSW:
5423return S32 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21
5424
5425case AREM, ASDIV:
5426return S64 | OPDP2(3)
5427
5428case AREMW, ASDIVW:
5429return S32 | OPDP2(3)
5430
5431case ASMULL, ASMADDL:
5432return OPDP3(1, 0, 1, 0)
5433
5434case ASMNEGL, ASMSUBL:
5435return OPDP3(1, 0, 1, 1)
5436
5437case ASMULH:
5438return OPDP3(1, 0, 2, 0)
5439
5440case AUMULL, AUMADDL:
5441return OPDP3(1, 0, 5, 0)
5442
5443case AUMNEGL, AUMSUBL:
5444return OPDP3(1, 0, 5, 1)
5445
5446case AUMULH:
5447return OPDP3(1, 0, 6, 0)
5448
5449case AUREM, AUDIV:
5450return S64 | OPDP2(2)
5451
5452case AUREMW, AUDIVW:
5453return S32 | OPDP2(2)
5454
5455case AAESE:
5456return 0x4E<<24 | 2<<20 | 8<<16 | 4<<12 | 2<<10
5457
5458case AAESD:
5459return 0x4E<<24 | 2<<20 | 8<<16 | 5<<12 | 2<<10
5460
5461case AAESMC:
5462return 0x4E<<24 | 2<<20 | 8<<16 | 6<<12 | 2<<10
5463
5464case AAESIMC:
5465return 0x4E<<24 | 2<<20 | 8<<16 | 7<<12 | 2<<10
5466
5467case ASHA1C:
5468return 0x5E<<24 | 0<<12
5469
5470case ASHA1P:
5471return 0x5E<<24 | 1<<12
5472
5473case ASHA1M:
5474return 0x5E<<24 | 2<<12
5475
5476case ASHA1SU0:
5477return 0x5E<<24 | 3<<12
5478
5479case ASHA256H:
5480return 0x5E<<24 | 4<<12
5481
5482case ASHA256H2:
5483return 0x5E<<24 | 5<<12
5484
5485case ASHA256SU1:
5486return 0x5E<<24 | 6<<12
5487
5488case ASHA1H:
5489return 0x5E<<24 | 2<<20 | 8<<16 | 0<<12 | 2<<10
5490
5491case ASHA1SU1:
5492return 0x5E<<24 | 2<<20 | 8<<16 | 1<<12 | 2<<10
5493
5494case ASHA256SU0:
5495return 0x5E<<24 | 2<<20 | 8<<16 | 2<<12 | 2<<10
5496
5497case ASHA512H:
5498return 0xCE<<24 | 3<<21 | 8<<12
5499
5500case ASHA512H2:
5501return 0xCE<<24 | 3<<21 | 8<<12 | 4<<8
5502
5503case ASHA512SU1:
5504return 0xCE<<24 | 3<<21 | 8<<12 | 8<<8
5505
5506case ASHA512SU0:
5507return 0xCE<<24 | 3<<22 | 8<<12
5508
5509case AFCVTZSD:
5510return FPCVTI(1, 0, 1, 3, 0)
5511
5512case AFCVTZSDW:
5513return FPCVTI(0, 0, 1, 3, 0)
5514
5515case AFCVTZSS:
5516return FPCVTI(1, 0, 0, 3, 0)
5517
5518case AFCVTZSSW:
5519return FPCVTI(0, 0, 0, 3, 0)
5520
5521case AFCVTZUD:
5522return FPCVTI(1, 0, 1, 3, 1)
5523
5524case AFCVTZUDW:
5525return FPCVTI(0, 0, 1, 3, 1)
5526
5527case AFCVTZUS:
5528return FPCVTI(1, 0, 0, 3, 1)
5529
5530case AFCVTZUSW:
5531return FPCVTI(0, 0, 0, 3, 1)
5532
5533case ASCVTFD:
5534return FPCVTI(1, 0, 1, 0, 2)
5535
5536case ASCVTFS:
5537return FPCVTI(1, 0, 0, 0, 2)
5538
5539case ASCVTFWD:
5540return FPCVTI(0, 0, 1, 0, 2)
5541
5542case ASCVTFWS:
5543return FPCVTI(0, 0, 0, 0, 2)
5544
5545case AUCVTFD:
5546return FPCVTI(1, 0, 1, 0, 3)
5547
5548case AUCVTFS:
5549return FPCVTI(1, 0, 0, 0, 3)
5550
5551case AUCVTFWD:
5552return FPCVTI(0, 0, 1, 0, 3)
5553
5554case AUCVTFWS:
5555return FPCVTI(0, 0, 0, 0, 3)
5556
5557case AFADDS:
5558return FPOP2S(0, 0, 0, 2)
5559
5560case AFADDD:
5561return FPOP2S(0, 0, 1, 2)
5562
5563case AFSUBS:
5564return FPOP2S(0, 0, 0, 3)
5565
5566case AFSUBD:
5567return FPOP2S(0, 0, 1, 3)
5568
5569case AFMADDD:
5570return FPOP3S(0, 0, 1, 0, 0)
5571
5572case AFMADDS:
5573return FPOP3S(0, 0, 0, 0, 0)
5574
5575case AFMSUBD:
5576return FPOP3S(0, 0, 1, 0, 1)
5577
5578case AFMSUBS:
5579return FPOP3S(0, 0, 0, 0, 1)
5580
5581case AFNMADDD:
5582return FPOP3S(0, 0, 1, 1, 0)
5583
5584case AFNMADDS:
5585return FPOP3S(0, 0, 0, 1, 0)
5586
5587case AFNMSUBD:
5588return FPOP3S(0, 0, 1, 1, 1)
5589
5590case AFNMSUBS:
5591return FPOP3S(0, 0, 0, 1, 1)
5592
5593case AFMULS:
5594return FPOP2S(0, 0, 0, 0)
5595
5596case AFMULD:
5597return FPOP2S(0, 0, 1, 0)
5598
5599case AFDIVS:
5600return FPOP2S(0, 0, 0, 1)
5601
5602case AFDIVD:
5603return FPOP2S(0, 0, 1, 1)
5604
5605case AFMAXS:
5606return FPOP2S(0, 0, 0, 4)
5607
5608case AFMINS:
5609return FPOP2S(0, 0, 0, 5)
5610
5611case AFMAXD:
5612return FPOP2S(0, 0, 1, 4)
5613
5614case AFMIND:
5615return FPOP2S(0, 0, 1, 5)
5616
5617case AFMAXNMS:
5618return FPOP2S(0, 0, 0, 6)
5619
5620case AFMAXNMD:
5621return FPOP2S(0, 0, 1, 6)
5622
5623case AFMINNMS:
5624return FPOP2S(0, 0, 0, 7)
5625
5626case AFMINNMD:
5627return FPOP2S(0, 0, 1, 7)
5628
5629case AFNMULS:
5630return FPOP2S(0, 0, 0, 8)
5631
5632case AFNMULD:
5633return FPOP2S(0, 0, 1, 8)
5634
5635case AFCMPS:
5636return FPCMP(0, 0, 0, 0, 0)
5637
5638case AFCMPD:
5639return FPCMP(0, 0, 1, 0, 0)
5640
5641case AFCMPES:
5642return FPCMP(0, 0, 0, 0, 16)
5643
5644case AFCMPED:
5645return FPCMP(0, 0, 1, 0, 16)
5646
5647case AFCCMPS:
5648return FPCCMP(0, 0, 0, 0)
5649
5650case AFCCMPD:
5651return FPCCMP(0, 0, 1, 0)
5652
5653case AFCCMPES:
5654return FPCCMP(0, 0, 0, 1)
5655
5656case AFCCMPED:
5657return FPCCMP(0, 0, 1, 1)
5658
5659case AFCSELS:
5660return 0x1E<<24 | 0<<22 | 1<<21 | 3<<10
5661
5662case AFCSELD:
5663return 0x1E<<24 | 1<<22 | 1<<21 | 3<<10
5664
5665case AFMOVS:
5666return FPOP1S(0, 0, 0, 0)
5667
5668case AFABSS:
5669return FPOP1S(0, 0, 0, 1)
5670
5671case AFNEGS:
5672return FPOP1S(0, 0, 0, 2)
5673
5674case AFSQRTS:
5675return FPOP1S(0, 0, 0, 3)
5676
5677case AFCVTSD:
5678return FPOP1S(0, 0, 0, 5)
5679
5680case AFCVTSH:
5681return FPOP1S(0, 0, 0, 7)
5682
5683case AFRINTNS:
5684return FPOP1S(0, 0, 0, 8)
5685
5686case AFRINTPS:
5687return FPOP1S(0, 0, 0, 9)
5688
5689case AFRINTMS:
5690return FPOP1S(0, 0, 0, 10)
5691
5692case AFRINTZS:
5693return FPOP1S(0, 0, 0, 11)
5694
5695case AFRINTAS:
5696return FPOP1S(0, 0, 0, 12)
5697
5698case AFRINTXS:
5699return FPOP1S(0, 0, 0, 14)
5700
5701case AFRINTIS:
5702return FPOP1S(0, 0, 0, 15)
5703
5704case AFMOVD:
5705return FPOP1S(0, 0, 1, 0)
5706
5707case AFABSD:
5708return FPOP1S(0, 0, 1, 1)
5709
5710case AFNEGD:
5711return FPOP1S(0, 0, 1, 2)
5712
5713case AFSQRTD:
5714return FPOP1S(0, 0, 1, 3)
5715
5716case AFCVTDS:
5717return FPOP1S(0, 0, 1, 4)
5718
5719case AFCVTDH:
5720return FPOP1S(0, 0, 1, 7)
5721
5722case AFRINTND:
5723return FPOP1S(0, 0, 1, 8)
5724
5725case AFRINTPD:
5726return FPOP1S(0, 0, 1, 9)
5727
5728case AFRINTMD:
5729return FPOP1S(0, 0, 1, 10)
5730
5731case AFRINTZD:
5732return FPOP1S(0, 0, 1, 11)
5733
5734case AFRINTAD:
5735return FPOP1S(0, 0, 1, 12)
5736
5737case AFRINTXD:
5738return FPOP1S(0, 0, 1, 14)
5739
5740case AFRINTID:
5741return FPOP1S(0, 0, 1, 15)
5742
5743case AFCVTHS:
5744return FPOP1S(0, 0, 3, 4)
5745
5746case AFCVTHD:
5747return FPOP1S(0, 0, 3, 5)
5748
5749case AVADD:
5750return 7<<25 | 1<<21 | 1<<15 | 1<<10
5751
5752case AVSUB:
5753return 0x17<<25 | 1<<21 | 1<<15 | 1<<10
5754
5755case AVADDP:
5756return 7<<25 | 1<<21 | 1<<15 | 15<<10
5757
5758case AVAND:
5759return 7<<25 | 1<<21 | 7<<10
5760
5761case AVCMEQ:
5762return 1<<29 | 0x71<<21 | 0x23<<10
5763
5764case AVCNT:
5765return 0xE<<24 | 0x10<<17 | 5<<12 | 2<<10
5766
5767case AVZIP1:
5768return 0xE<<24 | 3<<12 | 2<<10
5769
5770case AVZIP2:
5771return 0xE<<24 | 1<<14 | 3<<12 | 2<<10
5772
5773case AVEOR:
5774return 1<<29 | 0x71<<21 | 7<<10
5775
5776case AVORR:
5777return 7<<25 | 5<<21 | 7<<10
5778
5779case AVREV16:
5780return 3<<26 | 2<<24 | 1<<21 | 3<<11
5781
5782case AVREV32:
5783return 11<<26 | 2<<24 | 1<<21 | 1<<11
5784
5785case AVREV64:
5786return 3<<26 | 2<<24 | 1<<21 | 1<<11
5787
5788case AVMOV:
5789return 7<<25 | 5<<21 | 7<<10
5790
5791case AVADDV:
5792return 7<<25 | 3<<20 | 3<<15 | 7<<11
5793
5794case AVUADDLV:
5795return 1<<29 | 7<<25 | 3<<20 | 7<<11
5796
5797case AVFMLA:
5798return 7<<25 | 0<<23 | 1<<21 | 3<<14 | 3<<10
5799
5800case AVFMLS:
5801return 7<<25 | 1<<23 | 1<<21 | 3<<14 | 3<<10
5802
5803case AVPMULL, AVPMULL2:
5804return 0xE<<24 | 1<<21 | 0x38<<10
5805
5806case AVRBIT:
5807return 0x2E<<24 | 1<<22 | 0x10<<17 | 5<<12 | 2<<10
5808
5809case AVLD1, AVLD2, AVLD3, AVLD4:
5810return 3<<26 | 1<<22
5811
5812case AVLD1R, AVLD3R:
5813return 0xD<<24 | 1<<22
5814
5815case AVLD2R, AVLD4R:
5816return 0xD<<24 | 3<<21
5817
5818case AVBIF:
5819return 1<<29 | 7<<25 | 7<<21 | 7<<10
5820
5821case AVBIT:
5822return 1<<29 | 0x75<<21 | 7<<10
5823
5824case AVBSL:
5825return 1<<29 | 0x73<<21 | 7<<10
5826
5827case AVCMTST:
5828return 0xE<<24 | 1<<21 | 0x23<<10
5829
5830case AVUZP1:
5831return 7<<25 | 3<<11
5832
5833case AVUZP2:
5834return 7<<25 | 1<<14 | 3<<11
5835}
5836
5837c.ctxt.Diag("%v: bad rrr %d %v", p, a, a)
5838return 0
5839}
5840
5841/*
5842* imm -> Rd
5843* imm op Rn -> Rd
5844*/
5845func (c *ctxt7) opirr(p *obj.Prog, a obj.As) uint32 {
5846switch a {
5847/* op $addcon, Rn, Rd */
5848case AMOVD, AADD:
5849return S64 | 0<<30 | 0<<29 | 0x11<<24
5850
5851case ACMN, AADDS:
5852return S64 | 0<<30 | 1<<29 | 0x11<<24
5853
5854case AMOVW, AADDW:
5855return S32 | 0<<30 | 0<<29 | 0x11<<24
5856
5857case ACMNW, AADDSW:
5858return S32 | 0<<30 | 1<<29 | 0x11<<24
5859
5860case ASUB:
5861return S64 | 1<<30 | 0<<29 | 0x11<<24
5862
5863case ACMP, ASUBS:
5864return S64 | 1<<30 | 1<<29 | 0x11<<24
5865
5866case ASUBW:
5867return S32 | 1<<30 | 0<<29 | 0x11<<24
5868
5869case ACMPW, ASUBSW:
5870return S32 | 1<<30 | 1<<29 | 0x11<<24
5871
5872/* op $imm(SB), Rd; op label, Rd */
5873case AADR:
5874return 0<<31 | 0x10<<24
5875
5876case AADRP:
5877return 1<<31 | 0x10<<24
5878
5879/* op $bimm, Rn, Rd */
5880case AAND, ABIC:
5881return S64 | 0<<29 | 0x24<<23
5882
5883case AANDW, ABICW:
5884return S32 | 0<<29 | 0x24<<23 | 0<<22
5885
5886case AORR, AORN:
5887return S64 | 1<<29 | 0x24<<23
5888
5889case AORRW, AORNW:
5890return S32 | 1<<29 | 0x24<<23 | 0<<22
5891
5892case AEOR, AEON:
5893return S64 | 2<<29 | 0x24<<23
5894
5895case AEORW, AEONW:
5896return S32 | 2<<29 | 0x24<<23 | 0<<22
5897
5898case AANDS, ABICS, ATST:
5899return S64 | 3<<29 | 0x24<<23
5900
5901case AANDSW, ABICSW, ATSTW:
5902return S32 | 3<<29 | 0x24<<23 | 0<<22
5903
5904case AASR:
5905return S64 | 0<<29 | 0x26<<23 /* alias of SBFM */
5906
5907case AASRW:
5908return S32 | 0<<29 | 0x26<<23 | 0<<22
5909
5910/* op $width, $lsb, Rn, Rd */
5911case ABFI:
5912return S64 | 2<<29 | 0x26<<23 | 1<<22
5913/* alias of BFM */
5914
5915case ABFIW:
5916return S32 | 2<<29 | 0x26<<23 | 0<<22
5917
5918/* op $imms, $immr, Rn, Rd */
5919case ABFM:
5920return S64 | 1<<29 | 0x26<<23 | 1<<22
5921
5922case ABFMW:
5923return S32 | 1<<29 | 0x26<<23 | 0<<22
5924
5925case ASBFM:
5926return S64 | 0<<29 | 0x26<<23 | 1<<22
5927
5928case ASBFMW:
5929return S32 | 0<<29 | 0x26<<23 | 0<<22
5930
5931case AUBFM:
5932return S64 | 2<<29 | 0x26<<23 | 1<<22
5933
5934case AUBFMW:
5935return S32 | 2<<29 | 0x26<<23 | 0<<22
5936
5937case ABFXIL:
5938return S64 | 1<<29 | 0x26<<23 | 1<<22 /* alias of BFM */
5939
5940case ABFXILW:
5941return S32 | 1<<29 | 0x26<<23 | 0<<22
5942
5943case AEXTR:
5944return S64 | 0<<29 | 0x27<<23 | 1<<22 | 0<<21
5945
5946case AEXTRW:
5947return S32 | 0<<29 | 0x27<<23 | 0<<22 | 0<<21
5948
5949case ACBNZ:
5950return S64 | 0x1A<<25 | 1<<24
5951
5952case ACBNZW:
5953return S32 | 0x1A<<25 | 1<<24
5954
5955case ACBZ:
5956return S64 | 0x1A<<25 | 0<<24
5957
5958case ACBZW:
5959return S32 | 0x1A<<25 | 0<<24
5960
5961case ACCMN:
5962return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
5963
5964case ACCMNW:
5965return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4
5966
5967case ACCMP:
5968return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
5969
5970case ACCMPW:
5971return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4
5972
5973case AMOVK:
5974return S64 | 3<<29 | 0x25<<23
5975
5976case AMOVKW:
5977return S32 | 3<<29 | 0x25<<23
5978
5979case AMOVN:
5980return S64 | 0<<29 | 0x25<<23
5981
5982case AMOVNW:
5983return S32 | 0<<29 | 0x25<<23
5984
5985case AMOVZ:
5986return S64 | 2<<29 | 0x25<<23
5987
5988case AMOVZW:
5989return S32 | 2<<29 | 0x25<<23
5990
5991case AMSR:
5992return SYSOP(0, 0, 0, 4, 0, 0, 0x1F) /* MSR (immediate) */
5993
5994case AAT,
5995ADC,
5996AIC,
5997ATLBI,
5998ASYS:
5999return SYSOP(0, 1, 0, 0, 0, 0, 0)
6000
6001case ASYSL:
6002return SYSOP(1, 1, 0, 0, 0, 0, 0)
6003
6004case ATBZ:
6005return 0x36 << 24
6006
6007case ATBNZ:
6008return 0x37 << 24
6009
6010case ADSB:
6011return SYSOP(0, 0, 3, 3, 0, 4, 0x1F)
6012
6013case ADMB:
6014return SYSOP(0, 0, 3, 3, 0, 5, 0x1F)
6015
6016case AISB:
6017return SYSOP(0, 0, 3, 3, 0, 6, 0x1F)
6018
6019case AHINT:
6020return SYSOP(0, 0, 3, 2, 0, 0, 0x1F)
6021
6022case AVEXT:
6023return 0x2E<<24 | 0<<23 | 0<<21 | 0<<15
6024
6025case AVUSHR:
6026return 0x5E<<23 | 1<<10
6027
6028case AVSHL:
6029return 0x1E<<23 | 21<<10
6030
6031case AVSRI:
6032return 0x5E<<23 | 17<<10
6033
6034case AVUSHLL, AVUXTL:
6035return 1<<29 | 15<<24 | 0x29<<10
6036
6037case AVUSHLL2, AVUXTL2:
6038return 3<<29 | 15<<24 | 0x29<<10
6039}
6040
6041c.ctxt.Diag("%v: bad irr %v", p, a)
6042return 0
6043}
6044
6045func (c *ctxt7) opbit(p *obj.Prog, a obj.As) uint32 {
6046switch a {
6047case ACLS:
6048return S64 | OPBIT(5)
6049
6050case ACLSW:
6051return S32 | OPBIT(5)
6052
6053case ACLZ:
6054return S64 | OPBIT(4)
6055
6056case ACLZW:
6057return S32 | OPBIT(4)
6058
6059case ARBIT:
6060return S64 | OPBIT(0)
6061
6062case ARBITW:
6063return S32 | OPBIT(0)
6064
6065case AREV:
6066return S64 | OPBIT(3)
6067
6068case AREVW:
6069return S32 | OPBIT(2)
6070
6071case AREV16:
6072return S64 | OPBIT(1)
6073
6074case AREV16W:
6075return S32 | OPBIT(1)
6076
6077case AREV32:
6078return S64 | OPBIT(2)
6079
6080default:
6081c.ctxt.Diag("bad bit op\n%v", p)
6082return 0
6083}
6084}
6085
6086/*
6087* add/subtract sign or zero-extended register
6088*/
6089func (c *ctxt7) opxrrr(p *obj.Prog, a obj.As, extend bool) uint32 {
6090extension := uint32(0)
6091if !extend {
6092switch a {
6093case AADD, ACMN, AADDS, ASUB, ACMP, ASUBS:
6094extension = LSL0_64
6095
6096case AADDW, ACMNW, AADDSW, ASUBW, ACMPW, ASUBSW:
6097extension = LSL0_32
6098}
6099}
6100
6101switch a {
6102case AADD:
6103return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6104
6105case AADDW:
6106return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6107
6108case ACMN, AADDS:
6109return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6110
6111case ACMNW, AADDSW:
6112return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6113
6114case ASUB:
6115return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6116
6117case ASUBW:
6118return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6119
6120case ACMP, ASUBS:
6121return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6122
6123case ACMPW, ASUBSW:
6124return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | extension
6125}
6126
6127c.ctxt.Diag("bad opxrrr %v\n%v", a, p)
6128return 0
6129}
6130
6131func (c *ctxt7) opimm(p *obj.Prog, a obj.As) uint32 {
6132switch a {
6133case ASVC:
6134return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */
6135
6136case AHVC:
6137return 0xD4<<24 | 0<<21 | 2
6138
6139case ASMC:
6140return 0xD4<<24 | 0<<21 | 3
6141
6142case ABRK:
6143return 0xD4<<24 | 1<<21 | 0
6144
6145case AHLT:
6146return 0xD4<<24 | 2<<21 | 0
6147
6148case ADCPS1:
6149return 0xD4<<24 | 5<<21 | 1
6150
6151case ADCPS2:
6152return 0xD4<<24 | 5<<21 | 2
6153
6154case ADCPS3:
6155return 0xD4<<24 | 5<<21 | 3
6156
6157case ACLREX:
6158return SYSOP(0, 0, 3, 3, 0, 2, 0x1F)
6159}
6160
6161c.ctxt.Diag("%v: bad imm %v", p, a)
6162return 0
6163}
6164
6165func (c *ctxt7) brdist(p *obj.Prog, preshift int, flen int, shift int) int64 {
6166v := int64(0)
6167t := int64(0)
6168q := p.To.Target()
6169if q == nil {
6170// TODO: don't use brdist for this case, as it isn't a branch.
6171// (Calls from omovlit, and maybe adr/adrp opcodes as well.)
6172q = p.Pool
6173}
6174if q != nil {
6175v = (q.Pc >> uint(preshift)) - (c.pc >> uint(preshift))
6176if (v & ((1 << uint(shift)) - 1)) != 0 {
6177c.ctxt.Diag("misaligned label\n%v", p)
6178}
6179v >>= uint(shift)
6180t = int64(1) << uint(flen-1)
6181if v < -t || v >= t {
6182c.ctxt.Diag("branch too far %#x vs %#x [%p]\n%v\n%v", v, t, c.blitrl, p, q)
6183panic("branch too far")
6184}
6185}
6186
6187return v & ((t << 1) - 1)
6188}
6189
6190/*
6191* pc-relative branches
6192*/
6193func (c *ctxt7) opbra(p *obj.Prog, a obj.As) uint32 {
6194switch a {
6195case ABEQ:
6196return OPBcc(0x0)
6197
6198case ABNE:
6199return OPBcc(0x1)
6200
6201case ABCS:
6202return OPBcc(0x2)
6203
6204case ABHS:
6205return OPBcc(0x2)
6206
6207case ABCC:
6208return OPBcc(0x3)
6209
6210case ABLO:
6211return OPBcc(0x3)
6212
6213case ABMI:
6214return OPBcc(0x4)
6215
6216case ABPL:
6217return OPBcc(0x5)
6218
6219case ABVS:
6220return OPBcc(0x6)
6221
6222case ABVC:
6223return OPBcc(0x7)
6224
6225case ABHI:
6226return OPBcc(0x8)
6227
6228case ABLS:
6229return OPBcc(0x9)
6230
6231case ABGE:
6232return OPBcc(0xa)
6233
6234case ABLT:
6235return OPBcc(0xb)
6236
6237case ABGT:
6238return OPBcc(0xc)
6239
6240case ABLE:
6241return OPBcc(0xd) /* imm19<<5 | cond */
6242
6243case AB:
6244return 0<<31 | 5<<26 /* imm26 */
6245
6246case obj.ADUFFZERO, obj.ADUFFCOPY, ABL:
6247return 1<<31 | 5<<26
6248}
6249
6250c.ctxt.Diag("%v: bad bra %v", p, a)
6251return 0
6252}
6253
6254func (c *ctxt7) opbrr(p *obj.Prog, a obj.As) uint32 {
6255switch a {
6256case ABL:
6257return OPBLR(1) /* BLR */
6258
6259case AB:
6260return OPBLR(0) /* BR */
6261
6262case obj.ARET:
6263return OPBLR(2) /* RET */
6264}
6265
6266c.ctxt.Diag("%v: bad brr %v", p, a)
6267return 0
6268}
6269
6270func (c *ctxt7) op0(p *obj.Prog, a obj.As) uint32 {
6271switch a {
6272case ADRPS:
6273return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5
6274
6275case AERET:
6276return 0x6B<<25 | 4<<21 | 0x1F<<16 | 0<<10 | 0x1F<<5
6277
6278case ANOOP:
6279return SYSHINT(0)
6280
6281case AYIELD:
6282return SYSHINT(1)
6283
6284case AWFE:
6285return SYSHINT(2)
6286
6287case AWFI:
6288return SYSHINT(3)
6289
6290case ASEV:
6291return SYSHINT(4)
6292
6293case ASEVL:
6294return SYSHINT(5)
6295}
6296
6297c.ctxt.Diag("%v: bad op0 %v", p, a)
6298return 0
6299}
6300
6301/*
6302* register offset
6303*/
6304func (c *ctxt7) opload(p *obj.Prog, a obj.As) uint32 {
6305switch a {
6306case ALDAR:
6307return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10
6308
6309case ALDARW:
6310return LDSTX(2, 1, 1, 0, 1) | 0x1F<<10
6311
6312case ALDARB:
6313return LDSTX(0, 1, 1, 0, 1) | 0x1F<<10
6314
6315case ALDARH:
6316return LDSTX(1, 1, 1, 0, 1) | 0x1F<<10
6317
6318case ALDAXP:
6319return LDSTX(3, 0, 1, 1, 1)
6320
6321case ALDAXPW:
6322return LDSTX(2, 0, 1, 1, 1)
6323
6324case ALDAXR:
6325return LDSTX(3, 0, 1, 0, 1) | 0x1F<<10
6326
6327case ALDAXRW:
6328return LDSTX(2, 0, 1, 0, 1) | 0x1F<<10
6329
6330case ALDAXRB:
6331return LDSTX(0, 0, 1, 0, 1) | 0x1F<<10
6332
6333case ALDAXRH:
6334return LDSTX(1, 0, 1, 0, 1) | 0x1F<<10
6335
6336case ALDXR:
6337return LDSTX(3, 0, 1, 0, 0) | 0x1F<<10
6338
6339case ALDXRB:
6340return LDSTX(0, 0, 1, 0, 0) | 0x1F<<10
6341
6342case ALDXRH:
6343return LDSTX(1, 0, 1, 0, 0) | 0x1F<<10
6344
6345case ALDXRW:
6346return LDSTX(2, 0, 1, 0, 0) | 0x1F<<10
6347
6348case ALDXP:
6349return LDSTX(3, 0, 1, 1, 0)
6350
6351case ALDXPW:
6352return LDSTX(2, 0, 1, 1, 0)
6353
6354case AMOVNP:
6355return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
6356
6357case AMOVNPW:
6358return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
6359}
6360
6361c.ctxt.Diag("bad opload %v\n%v", a, p)
6362return 0
6363}
6364
6365func (c *ctxt7) opstore(p *obj.Prog, a obj.As) uint32 {
6366switch a {
6367case ASTLR:
6368return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10
6369
6370case ASTLRB:
6371return LDSTX(0, 1, 0, 0, 1) | 0x1F<<10
6372
6373case ASTLRH:
6374return LDSTX(1, 1, 0, 0, 1) | 0x1F<<10
6375
6376case ASTLP:
6377return LDSTX(3, 0, 0, 1, 1)
6378
6379case ASTLPW:
6380return LDSTX(2, 0, 0, 1, 1)
6381
6382case ASTLRW:
6383return LDSTX(2, 1, 0, 0, 1) | 0x1F<<10
6384
6385case ASTLXP:
6386return LDSTX(3, 0, 0, 1, 1)
6387
6388case ASTLXPW:
6389return LDSTX(2, 0, 0, 1, 1)
6390
6391case ASTLXR:
6392return LDSTX(3, 0, 0, 0, 1) | 0x1F<<10
6393
6394case ASTLXRB:
6395return LDSTX(0, 0, 0, 0, 1) | 0x1F<<10
6396
6397case ASTLXRH:
6398return LDSTX(1, 0, 0, 0, 1) | 0x1F<<10
6399
6400case ASTLXRW:
6401return LDSTX(2, 0, 0, 0, 1) | 0x1F<<10
6402
6403case ASTXR:
6404return LDSTX(3, 0, 0, 0, 0) | 0x1F<<10
6405
6406case ASTXRB:
6407return LDSTX(0, 0, 0, 0, 0) | 0x1F<<10
6408
6409case ASTXRH:
6410return LDSTX(1, 0, 0, 0, 0) | 0x1F<<10
6411
6412case ASTXP:
6413return LDSTX(3, 0, 0, 1, 0)
6414
6415case ASTXPW:
6416return LDSTX(2, 0, 0, 1, 0)
6417
6418case ASTXRW:
6419return LDSTX(2, 0, 0, 0, 0) | 0x1F<<10
6420
6421case AMOVNP:
6422return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
6423
6424case AMOVNPW:
6425return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
6426}
6427
6428c.ctxt.Diag("bad opstore %v\n%v", a, p)
6429return 0
6430}
6431
6432/*
6433* load/store register (unsigned immediate) C3.3.13
6434* these produce 64-bit values (when there's an option)
6435*/
6436func (c *ctxt7) olsr12u(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
6437if v < 0 || v >= (1<<12) {
6438c.ctxt.Diag("offset out of range: %d\n%v", v, p)
6439}
6440o |= (v & 0xFFF) << 10
6441o |= int32(b&31) << 5
6442o |= int32(r & 31)
6443return uint32(o)
6444}
6445
6446func (c *ctxt7) opldr12(p *obj.Prog, a obj.As) uint32 {
6447switch a {
6448case AMOVD:
6449return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */
6450
6451case AMOVW:
6452return LDSTR12U(2, 0, 2)
6453
6454case AMOVWU:
6455return LDSTR12U(2, 0, 1)
6456
6457case AMOVH:
6458return LDSTR12U(1, 0, 2)
6459
6460case AMOVHU:
6461return LDSTR12U(1, 0, 1)
6462
6463case AMOVB:
6464return LDSTR12U(0, 0, 2)
6465
6466case AMOVBU:
6467return LDSTR12U(0, 0, 1)
6468
6469case AFMOVS:
6470return LDSTR12U(2, 1, 1)
6471
6472case AFMOVD:
6473return LDSTR12U(3, 1, 1)
6474}
6475
6476c.ctxt.Diag("bad opldr12 %v\n%v", a, p)
6477return 0
6478}
6479
6480func (c *ctxt7) opstr12(p *obj.Prog, a obj.As) uint32 {
6481return LD2STR(c.opldr12(p, a))
6482}
6483
6484/*
6485* load/store register (unscaled immediate) C3.3.12
6486*/
6487func (c *ctxt7) olsr9s(p *obj.Prog, o int32, v int32, b int, r int) uint32 {
6488if v < -256 || v > 255 {
6489c.ctxt.Diag("offset out of range: %d\n%v", v, p)
6490}
6491o |= (v & 0x1FF) << 12
6492o |= int32(b&31) << 5
6493o |= int32(r & 31)
6494return uint32(o)
6495}
6496
6497func (c *ctxt7) opldr9(p *obj.Prog, a obj.As) uint32 {
6498switch a {
6499case AMOVD:
6500return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
6501
6502case AMOVW:
6503return LDSTR9S(2, 0, 2)
6504
6505case AMOVWU:
6506return LDSTR9S(2, 0, 1)
6507
6508case AMOVH:
6509return LDSTR9S(1, 0, 2)
6510
6511case AMOVHU:
6512return LDSTR9S(1, 0, 1)
6513
6514case AMOVB:
6515return LDSTR9S(0, 0, 2)
6516
6517case AMOVBU:
6518return LDSTR9S(0, 0, 1)
6519
6520case AFMOVS:
6521return LDSTR9S(2, 1, 1)
6522
6523case AFMOVD:
6524return LDSTR9S(3, 1, 1)
6525}
6526
6527c.ctxt.Diag("bad opldr9 %v\n%v", a, p)
6528return 0
6529}
6530
6531func (c *ctxt7) opstr9(p *obj.Prog, a obj.As) uint32 {
6532return LD2STR(c.opldr9(p, a))
6533}
6534
6535func (c *ctxt7) opldrpp(p *obj.Prog, a obj.As) uint32 {
6536switch a {
6537case AMOVD:
6538return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */
6539
6540case AMOVW:
6541return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
6542
6543case AMOVWU:
6544return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
6545
6546case AMOVH:
6547return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
6548
6549case AMOVHU:
6550return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
6551
6552case AMOVB:
6553return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
6554
6555case AMOVBU:
6556return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
6557
6558case AFMOVS:
6559return 2<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
6560
6561case AFMOVD:
6562return 3<<30 | 7<<27 | 1<<26 | 0<<24 | 1<<22
6563
6564case APRFM:
6565return 0xf9<<24 | 2<<22
6566
6567}
6568
6569c.ctxt.Diag("bad opldr %v\n%v", a, p)
6570return 0
6571}
6572
6573// olsxrr attaches register operands to a load/store opcode supplied in o.
6574// The result either encodes a load of r from (r1+r2) or a store of r to (r1+r2).
6575func (c *ctxt7) olsxrr(p *obj.Prog, o int32, r int, r1 int, r2 int) uint32 {
6576o |= int32(r1&31) << 5
6577o |= int32(r2&31) << 16
6578o |= int32(r & 31)
6579return uint32(o)
6580}
6581
6582// opldrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
6583// for load instruction with register offset.
6584// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm).
6585func (c *ctxt7) opldrr(p *obj.Prog, a obj.As, extension bool) uint32 {
6586OptionS := uint32(0x1a)
6587if extension {
6588OptionS = uint32(0) // option value and S value have been encoded into p.From.Offset.
6589}
6590switch a {
6591case AMOVD:
6592return OptionS<<10 | 0x3<<21 | 0x1f<<27
6593case AMOVW:
6594return OptionS<<10 | 0x5<<21 | 0x17<<27
6595case AMOVWU:
6596return OptionS<<10 | 0x3<<21 | 0x17<<27
6597case AMOVH:
6598return OptionS<<10 | 0x5<<21 | 0x0f<<27
6599case AMOVHU:
6600return OptionS<<10 | 0x3<<21 | 0x0f<<27
6601case AMOVB:
6602return OptionS<<10 | 0x5<<21 | 0x07<<27
6603case AMOVBU:
6604return OptionS<<10 | 0x3<<21 | 0x07<<27
6605case AFMOVS:
6606return OptionS<<10 | 0x3<<21 | 0x17<<27 | 1<<26
6607case AFMOVD:
6608return OptionS<<10 | 0x3<<21 | 0x1f<<27 | 1<<26
6609}
6610c.ctxt.Diag("bad opldrr %v\n%v", a, p)
6611return 0
6612}
6613
6614// opstrr returns the ARM64 opcode encoding corresponding to the obj.As opcode
6615// for store instruction with register offset.
6616// The offset register can be (Rn)(Rm.UXTW<<2) or (Rn)(Rm<<2) or (Rn)(Rm).
6617func (c *ctxt7) opstrr(p *obj.Prog, a obj.As, extension bool) uint32 {
6618OptionS := uint32(0x1a)
6619if extension {
6620OptionS = uint32(0) // option value and S value have been encoded into p.To.Offset.
6621}
6622switch a {
6623case AMOVD:
6624return OptionS<<10 | 0x1<<21 | 0x1f<<27
6625case AMOVW, AMOVWU:
6626return OptionS<<10 | 0x1<<21 | 0x17<<27
6627case AMOVH, AMOVHU:
6628return OptionS<<10 | 0x1<<21 | 0x0f<<27
6629case AMOVB, AMOVBU:
6630return OptionS<<10 | 0x1<<21 | 0x07<<27
6631case AFMOVS:
6632return OptionS<<10 | 0x1<<21 | 0x17<<27 | 1<<26
6633case AFMOVD:
6634return OptionS<<10 | 0x1<<21 | 0x1f<<27 | 1<<26
6635}
6636c.ctxt.Diag("bad opstrr %v\n%v", a, p)
6637return 0
6638}
6639
6640func (c *ctxt7) oaddi(p *obj.Prog, o1 int32, v int32, r int, rt int) uint32 {
6641if (v & 0xFFF000) != 0 {
6642if v&0xFFF != 0 {
6643c.ctxt.Diag("%v misuses oaddi", p)
6644}
6645v >>= 12
6646o1 |= 1 << 22
6647}
6648
6649o1 |= ((v & 0xFFF) << 10) | (int32(r&31) << 5) | int32(rt&31)
6650return uint32(o1)
6651}
6652
6653/*
6654* load a literal value into dr
6655*/
6656func (c *ctxt7) omovlit(as obj.As, p *obj.Prog, a *obj.Addr, dr int) uint32 {
6657var o1 int32
6658if p.Pool == nil { /* not in literal pool */
6659c.aclass(a)
6660c.ctxt.Logf("omovlit add %d (%#x)\n", c.instoffset, uint64(c.instoffset))
6661
6662/* TODO: could be clever, and use general constant builder */
6663o1 = int32(c.opirr(p, AADD))
6664
6665v := int32(c.instoffset)
6666if v != 0 && (v&0xFFF) == 0 {
6667v >>= 12
6668o1 |= 1 << 22 /* shift, by 12 */
6669}
6670
6671o1 |= ((v & 0xFFF) << 10) | (REGZERO & 31 << 5) | int32(dr&31)
6672} else {
6673fp, w := 0, 0
6674switch as {
6675case AFMOVS:
6676fp = 1
6677w = 0 /* 32-bit SIMD/FP */
6678
6679case AFMOVD:
6680fp = 1
6681w = 1 /* 64-bit SIMD/FP */
6682
6683case AFMOVQ:
6684fp = 1
6685w = 2 /* 128-bit SIMD/FP */
6686
6687case AMOVD:
6688if p.Pool.As == ADWORD {
6689w = 1 /* 64-bit */
6690} else if p.Pool.To.Offset < 0 {
6691w = 2 /* 32-bit, sign-extended to 64-bit */
6692} else if p.Pool.To.Offset >= 0 {
6693w = 0 /* 32-bit, zero-extended to 64-bit */
6694} else {
6695c.ctxt.Diag("invalid operand %v in %v", a, p)
6696}
6697
6698case AMOVBU, AMOVHU, AMOVWU:
6699w = 0 /* 32-bit, zero-extended to 64-bit */
6700
6701case AMOVB, AMOVH, AMOVW:
6702w = 2 /* 32-bit, sign-extended to 64-bit */
6703
6704default:
6705c.ctxt.Diag("invalid operation %v in %v", as, p)
6706}
6707
6708v := int32(c.brdist(p, 0, 19, 2))
6709o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27)
6710o1 |= (v & 0x7FFFF) << 5
6711o1 |= int32(dr & 31)
6712}
6713
6714return uint32(o1)
6715}
6716
6717// load a constant (MOVCON or BITCON) in a into rt
6718func (c *ctxt7) omovconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int) (o1 uint32) {
6719if cls := oclass(a); cls == C_BITCON || cls == C_ABCON || cls == C_ABCON0 {
6720// or $bitcon, REGZERO, rt
6721mode := 64
6722var as1 obj.As
6723switch as {
6724case AMOVW:
6725as1 = AORRW
6726mode = 32
6727case AMOVD:
6728as1 = AORR
6729}
6730o1 = c.opirr(p, as1)
6731o1 |= bitconEncode(uint64(a.Offset), mode) | uint32(REGZERO&31)<<5 | uint32(rt&31)
6732return o1
6733}
6734
6735if as == AMOVW {
6736d := uint32(a.Offset)
6737s := movcon(int64(d))
6738if s < 0 || 16*s >= 32 {
6739d = ^d
6740s = movcon(int64(d))
6741if s < 0 || 16*s >= 32 {
6742c.ctxt.Diag("impossible 32-bit move wide: %#x\n%v", uint32(a.Offset), p)
6743}
6744o1 = c.opirr(p, AMOVNW)
6745} else {
6746o1 = c.opirr(p, AMOVZW)
6747}
6748o1 |= MOVCONST(int64(d), s, rt)
6749}
6750if as == AMOVD {
6751d := a.Offset
6752s := movcon(d)
6753if s < 0 || 16*s >= 64 {
6754d = ^d
6755s = movcon(d)
6756if s < 0 || 16*s >= 64 {
6757c.ctxt.Diag("impossible 64-bit move wide: %#x\n%v", uint64(a.Offset), p)
6758}
6759o1 = c.opirr(p, AMOVN)
6760} else {
6761o1 = c.opirr(p, AMOVZ)
6762}
6763o1 |= MOVCONST(d, s, rt)
6764}
6765return o1
6766}
6767
6768// load a 32-bit/64-bit large constant (LCON or VCON) in a.Offset into rt
6769// put the instruction sequence in os and return the number of instructions.
6770func (c *ctxt7) omovlconst(as obj.As, p *obj.Prog, a *obj.Addr, rt int, os []uint32) (num uint8) {
6771switch as {
6772case AMOVW:
6773d := uint32(a.Offset)
6774// use MOVZW and MOVKW to load a constant to rt
6775os[0] = c.opirr(p, AMOVZW)
6776os[0] |= MOVCONST(int64(d), 0, rt)
6777os[1] = c.opirr(p, AMOVKW)
6778os[1] |= MOVCONST(int64(d), 1, rt)
6779return 2
6780
6781case AMOVD:
6782d := a.Offset
6783dn := ^d
6784var immh [4]uint64
6785var i int
6786zeroCount := int(0)
6787negCount := int(0)
6788for i = 0; i < 4; i++ {
6789immh[i] = uint64((d >> uint(i*16)) & 0xffff)
6790if immh[i] == 0 {
6791zeroCount++
6792} else if immh[i] == 0xffff {
6793negCount++
6794}
6795}
6796
6797if zeroCount == 4 || negCount == 4 {
6798c.ctxt.Diag("the immediate should be MOVCON: %v", p)
6799}
6800switch {
6801case zeroCount == 3:
6802// one MOVZ
6803for i = 0; i < 4; i++ {
6804if immh[i] != 0 {
6805os[0] = c.opirr(p, AMOVZ)
6806os[0] |= MOVCONST(d, i, rt)
6807break
6808}
6809}
6810return 1
6811
6812case negCount == 3:
6813// one MOVN
6814for i = 0; i < 4; i++ {
6815if immh[i] != 0xffff {
6816os[0] = c.opirr(p, AMOVN)
6817os[0] |= MOVCONST(dn, i, rt)
6818break
6819}
6820}
6821return 1
6822
6823case zeroCount == 2:
6824// one MOVZ and one MOVK
6825for i = 0; i < 4; i++ {
6826if immh[i] != 0 {
6827os[0] = c.opirr(p, AMOVZ)
6828os[0] |= MOVCONST(d, i, rt)
6829i++
6830break
6831}
6832}
6833for ; i < 4; i++ {
6834if immh[i] != 0 {
6835os[1] = c.opirr(p, AMOVK)
6836os[1] |= MOVCONST(d, i, rt)
6837}
6838}
6839return 2
6840
6841case negCount == 2:
6842// one MOVN and one MOVK
6843for i = 0; i < 4; i++ {
6844if immh[i] != 0xffff {
6845os[0] = c.opirr(p, AMOVN)
6846os[0] |= MOVCONST(dn, i, rt)
6847i++
6848break
6849}
6850}
6851for ; i < 4; i++ {
6852if immh[i] != 0xffff {
6853os[1] = c.opirr(p, AMOVK)
6854os[1] |= MOVCONST(d, i, rt)
6855}
6856}
6857return 2
6858
6859case zeroCount == 1:
6860// one MOVZ and two MOVKs
6861for i = 0; i < 4; i++ {
6862if immh[i] != 0 {
6863os[0] = c.opirr(p, AMOVZ)
6864os[0] |= MOVCONST(d, i, rt)
6865i++
6866break
6867}
6868}
6869
6870for j := 1; i < 4; i++ {
6871if immh[i] != 0 {
6872os[j] = c.opirr(p, AMOVK)
6873os[j] |= MOVCONST(d, i, rt)
6874j++
6875}
6876}
6877return 3
6878
6879case negCount == 1:
6880// one MOVN and two MOVKs
6881for i = 0; i < 4; i++ {
6882if immh[i] != 0xffff {
6883os[0] = c.opirr(p, AMOVN)
6884os[0] |= MOVCONST(dn, i, rt)
6885i++
6886break
6887}
6888}
6889
6890for j := 1; i < 4; i++ {
6891if immh[i] != 0xffff {
6892os[j] = c.opirr(p, AMOVK)
6893os[j] |= MOVCONST(d, i, rt)
6894j++
6895}
6896}
6897return 3
6898
6899default:
6900// one MOVZ and 3 MOVKs
6901os[0] = c.opirr(p, AMOVZ)
6902os[0] |= MOVCONST(d, 0, rt)
6903for i = 1; i < 4; i++ {
6904os[i] = c.opirr(p, AMOVK)
6905os[i] |= MOVCONST(d, i, rt)
6906}
6907return 4
6908}
6909default:
6910return 0
6911}
6912}
6913
6914func (c *ctxt7) opbfm(p *obj.Prog, a obj.As, r int, s int, rf int, rt int) uint32 {
6915var b uint32
6916o := c.opirr(p, a)
6917if (o & (1 << 31)) == 0 {
6918b = 32
6919} else {
6920b = 64
6921}
6922if r < 0 || uint32(r) >= b {
6923c.ctxt.Diag("illegal bit number\n%v", p)
6924}
6925o |= (uint32(r) & 0x3F) << 16
6926if s < 0 || uint32(s) >= b {
6927c.ctxt.Diag("illegal bit number\n%v", p)
6928}
6929o |= (uint32(s) & 0x3F) << 10
6930o |= (uint32(rf&31) << 5) | uint32(rt&31)
6931return o
6932}
6933
6934func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) uint32 {
6935var b uint32
6936o := c.opirr(p, a)
6937if (o & (1 << 31)) != 0 {
6938b = 63
6939} else {
6940b = 31
6941}
6942if v < 0 || uint32(v) > b {
6943c.ctxt.Diag("illegal bit number\n%v", p)
6944}
6945o |= uint32(v) << 10
6946o |= uint32(rn&31) << 5
6947o |= uint32(rm&31) << 16
6948o |= uint32(rt & 31)
6949return o
6950}
6951
6952/* genrate instruction encoding for LDP/LDPW/LDPSW/STP/STPW */
6953func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uint32) uint32 {
6954wback := false
6955if o.scond == C_XPOST || o.scond == C_XPRE {
6956wback = true
6957}
6958switch p.As {
6959case ALDP, ALDPW, ALDPSW:
6960c.checkUnpredictable(p, true, wback, p.From.Reg, p.To.Reg, int16(p.To.Offset))
6961case ASTP, ASTPW:
6962if wback == true {
6963c.checkUnpredictable(p, false, true, p.To.Reg, p.From.Reg, int16(p.From.Offset))
6964}
6965case AFLDPD, AFLDPS:
6966c.checkUnpredictable(p, true, false, p.From.Reg, p.To.Reg, int16(p.To.Offset))
6967}
6968var ret uint32
6969// check offset
6970switch p.As {
6971case AFLDPD, AFSTPD:
6972if vo < -512 || vo > 504 || vo%8 != 0 {
6973c.ctxt.Diag("invalid offset %v\n", p)
6974}
6975vo /= 8
6976ret = 1<<30 | 1<<26
6977case ALDP, ASTP:
6978if vo < -512 || vo > 504 || vo%8 != 0 {
6979c.ctxt.Diag("invalid offset %v\n", p)
6980}
6981vo /= 8
6982ret = 2 << 30
6983case AFLDPS, AFSTPS:
6984if vo < -256 || vo > 252 || vo%4 != 0 {
6985c.ctxt.Diag("invalid offset %v\n", p)
6986}
6987vo /= 4
6988ret = 1 << 26
6989case ALDPW, ASTPW:
6990if vo < -256 || vo > 252 || vo%4 != 0 {
6991c.ctxt.Diag("invalid offset %v\n", p)
6992}
6993vo /= 4
6994ret = 0
6995case ALDPSW:
6996if vo < -256 || vo > 252 || vo%4 != 0 {
6997c.ctxt.Diag("invalid offset %v\n", p)
6998}
6999vo /= 4
7000ret = 1 << 30
7001default:
7002c.ctxt.Diag("invalid instruction %v\n", p)
7003}
7004// check register pair
7005switch p.As {
7006case AFLDPD, AFLDPS, AFSTPD, AFSTPS:
7007if rl < REG_F0 || REG_F31 < rl || rh < REG_F0 || REG_F31 < rh {
7008c.ctxt.Diag("invalid register pair %v\n", p)
7009}
7010case ALDP, ALDPW, ALDPSW:
7011if rl < REG_R0 || REG_R30 < rl || rh < REG_R0 || REG_R30 < rh {
7012c.ctxt.Diag("invalid register pair %v\n", p)
7013}
7014case ASTP, ASTPW:
7015if rl < REG_R0 || REG_R31 < rl || rh < REG_R0 || REG_R31 < rh {
7016c.ctxt.Diag("invalid register pair %v\n", p)
7017}
7018}
7019// other conditional flag bits
7020switch o.scond {
7021case C_XPOST:
7022ret |= 1 << 23
7023case C_XPRE:
7024ret |= 3 << 23
7025default:
7026ret |= 2 << 23
7027}
7028ret |= 5<<27 | (ldp&1)<<22 | uint32(vo&0x7f)<<15 | (rh&31)<<10 | (rbase&31)<<5 | (rl & 31)
7029return ret
7030}
7031
7032func (c *ctxt7) maskOpvldvst(p *obj.Prog, o1 uint32) uint32 {
7033if p.As == AVLD1 || p.As == AVST1 {
7034return o1
7035}
7036
7037o1 &^= 0xf000 // mask out "opcode" field (bit 12-15)
7038switch p.As {
7039case AVLD1R, AVLD2R:
7040o1 |= 0xC << 12
7041case AVLD3R, AVLD4R:
7042o1 |= 0xE << 12
7043case AVLD2, AVST2:
7044o1 |= 8 << 12
7045case AVLD3, AVST3:
7046o1 |= 4 << 12
7047case AVLD4, AVST4:
7048default:
7049c.ctxt.Diag("unsupported instruction:%v\n", p.As)
7050}
7051return o1
7052}
7053
7054/*
7055* size in log2(bytes)
7056*/
7057func movesize(a obj.As) int {
7058switch a {
7059case AMOVD:
7060return 3
7061
7062case AMOVW, AMOVWU:
7063return 2
7064
7065case AMOVH, AMOVHU:
7066return 1
7067
7068case AMOVB, AMOVBU:
7069return 0
7070
7071case AFMOVS:
7072return 2
7073
7074case AFMOVD:
7075return 3
7076
7077default:
7078return -1
7079}
7080}
7081
7082// rm is the Rm register value, o is the extension, amount is the left shift value.
7083func roff(rm int16, o uint32, amount int16) uint32 {
7084return uint32(rm&31)<<16 | o<<13 | uint32(amount)<<10
7085}
7086
7087// encRegShiftOrExt returns the encoding of shifted/extended register, Rx<<n and Rx.UXTW<<n, etc.
7088func (c *ctxt7) encRegShiftOrExt(a *obj.Addr, r int16) uint32 {
7089var num, rm int16
7090num = (r >> 5) & 7
7091rm = r & 31
7092switch {
7093case REG_UXTB <= r && r < REG_UXTH:
7094return roff(rm, 0, num)
7095case REG_UXTH <= r && r < REG_UXTW:
7096return roff(rm, 1, num)
7097case REG_UXTW <= r && r < REG_UXTX:
7098if a.Type == obj.TYPE_MEM {
7099if num == 0 {
7100return roff(rm, 2, 2)
7101} else {
7102return roff(rm, 2, 6)
7103}
7104} else {
7105return roff(rm, 2, num)
7106}
7107case REG_UXTX <= r && r < REG_SXTB:
7108return roff(rm, 3, num)
7109case REG_SXTB <= r && r < REG_SXTH:
7110return roff(rm, 4, num)
7111case REG_SXTH <= r && r < REG_SXTW:
7112return roff(rm, 5, num)
7113case REG_SXTW <= r && r < REG_SXTX:
7114if a.Type == obj.TYPE_MEM {
7115if num == 0 {
7116return roff(rm, 6, 2)
7117} else {
7118return roff(rm, 6, 6)
7119}
7120} else {
7121return roff(rm, 6, num)
7122}
7123case REG_SXTX <= r && r < REG_SPECIAL:
7124if a.Type == obj.TYPE_MEM {
7125if num == 0 {
7126return roff(rm, 7, 2)
7127} else {
7128return roff(rm, 7, 6)
7129}
7130} else {
7131return roff(rm, 7, num)
7132}
7133case REG_LSL <= r && r < (REG_LSL+1<<8):
7134return roff(rm, 3, 6)
7135default:
7136c.ctxt.Diag("unsupported register extension type.")
7137}
7138
7139return 0
7140}
7141