1// cmd/7l/list.c and cmd/7l/sub.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	"cmd/internal/obj"
35	"fmt"
36)
37
38var strcond = [16]string{
39	"EQ",
40	"NE",
41	"HS",
42	"LO",
43	"MI",
44	"PL",
45	"VS",
46	"VC",
47	"HI",
48	"LS",
49	"GE",
50	"LT",
51	"GT",
52	"LE",
53	"AL",
54	"NV",
55}
56
57func init() {
58	obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, rconv)
59	obj.RegisterOpcode(obj.ABaseARM64, Anames)
60	obj.RegisterRegisterList(obj.RegListARM64Lo, obj.RegListARM64Hi, rlconv)
61	obj.RegisterOpSuffix("arm64", obj.CConvARM)
62}
63
64func arrange(a int) string {
65	switch a {
66	case ARNG_8B:
67		return "B8"
68	case ARNG_16B:
69		return "B16"
70	case ARNG_4H:
71		return "H4"
72	case ARNG_8H:
73		return "H8"
74	case ARNG_2S:
75		return "S2"
76	case ARNG_4S:
77		return "S4"
78	case ARNG_1D:
79		return "D1"
80	case ARNG_2D:
81		return "D2"
82	case ARNG_B:
83		return "B"
84	case ARNG_H:
85		return "H"
86	case ARNG_S:
87		return "S"
88	case ARNG_D:
89		return "D"
90	case ARNG_1Q:
91		return "Q1"
92	default:
93		return ""
94	}
95}
96
97func rconv(r int) string {
98	ext := (r >> 5) & 7
99	if r == REGG {
100		return "g"
101	}
102	switch {
103	case REG_R0 <= r && r <= REG_R30:
104		return fmt.Sprintf("R%d", r-REG_R0)
105	case r == REG_R31:
106		return "ZR"
107	case REG_F0 <= r && r <= REG_F31:
108		return fmt.Sprintf("F%d", r-REG_F0)
109	case REG_V0 <= r && r <= REG_V31:
110		return fmt.Sprintf("V%d", r-REG_V0)
111	case COND_EQ <= r && r <= COND_NV:
112		return strcond[r-COND_EQ]
113	case r == REGSP:
114		return "RSP"
115	case r == REG_DAIFSet:
116		return "DAIFSet"
117	case r == REG_DAIFClr:
118		return "DAIFClr"
119	case r == REG_PLDL1KEEP:
120		return "PLDL1KEEP"
121	case r == REG_PLDL1STRM:
122		return "PLDL1STRM"
123	case r == REG_PLDL2KEEP:
124		return "PLDL2KEEP"
125	case r == REG_PLDL2STRM:
126		return "PLDL2STRM"
127	case r == REG_PLDL3KEEP:
128		return "PLDL3KEEP"
129	case r == REG_PLDL3STRM:
130		return "PLDL3STRM"
131	case r == REG_PLIL1KEEP:
132		return "PLIL1KEEP"
133	case r == REG_PLIL1STRM:
134		return "PLIL1STRM"
135	case r == REG_PLIL2KEEP:
136		return "PLIL2KEEP"
137	case r == REG_PLIL2STRM:
138		return "PLIL2STRM"
139	case r == REG_PLIL3KEEP:
140		return "PLIL3KEEP"
141	case r == REG_PLIL3STRM:
142		return "PLIL3STRM"
143	case r == REG_PSTL1KEEP:
144		return "PSTL1KEEP"
145	case r == REG_PSTL1STRM:
146		return "PSTL1STRM"
147	case r == REG_PSTL2KEEP:
148		return "PSTL2KEEP"
149	case r == REG_PSTL2STRM:
150		return "PSTL2STRM"
151	case r == REG_PSTL3KEEP:
152		return "PSTL3KEEP"
153	case r == REG_PSTL3STRM:
154		return "PSTL3STRM"
155	case REG_UXTB <= r && r < REG_UXTH:
156		if ext != 0 {
157			return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext)
158		} else {
159			return fmt.Sprintf("%s.UXTB", regname(r))
160		}
161	case REG_UXTH <= r && r < REG_UXTW:
162		if ext != 0 {
163			return fmt.Sprintf("%s.UXTH<<%d", regname(r), ext)
164		} else {
165			return fmt.Sprintf("%s.UXTH", regname(r))
166		}
167	case REG_UXTW <= r && r < REG_UXTX:
168		if ext != 0 {
169			return fmt.Sprintf("%s.UXTW<<%d", regname(r), ext)
170		} else {
171			return fmt.Sprintf("%s.UXTW", regname(r))
172		}
173	case REG_UXTX <= r && r < REG_SXTB:
174		if ext != 0 {
175			return fmt.Sprintf("%s.UXTX<<%d", regname(r), ext)
176		} else {
177			return fmt.Sprintf("%s.UXTX", regname(r))
178		}
179	case REG_SXTB <= r && r < REG_SXTH:
180		if ext != 0 {
181			return fmt.Sprintf("%s.SXTB<<%d", regname(r), ext)
182		} else {
183			return fmt.Sprintf("%s.SXTB", regname(r))
184		}
185	case REG_SXTH <= r && r < REG_SXTW:
186		if ext != 0 {
187			return fmt.Sprintf("%s.SXTH<<%d", regname(r), ext)
188		} else {
189			return fmt.Sprintf("%s.SXTH", regname(r))
190		}
191	case REG_SXTW <= r && r < REG_SXTX:
192		if ext != 0 {
193			return fmt.Sprintf("%s.SXTW<<%d", regname(r), ext)
194		} else {
195			return fmt.Sprintf("%s.SXTW", regname(r))
196		}
197	case REG_SXTX <= r && r < REG_SPECIAL:
198		if ext != 0 {
199			return fmt.Sprintf("%s.SXTX<<%d", regname(r), ext)
200		} else {
201			return fmt.Sprintf("%s.SXTX", regname(r))
202		}
203	// bits 0-4 indicate register, bits 5-7 indicate shift amount, bit 8 equals to 0.
204	case REG_LSL <= r && r < (REG_LSL+1<<8):
205		return fmt.Sprintf("R%d<<%d", r&31, (r>>5)&7)
206	case REG_ARNG <= r && r < REG_ELEM:
207		return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15))
208	case REG_ELEM <= r && r < REG_ELEM_END:
209		return fmt.Sprintf("V%d.%s", r&31, arrange((r>>5)&15))
210	}
211	// Return system register name.
212	name, _, _ := SysRegEnc(int16(r))
213	if name != "" {
214		return name
215	}
216	return fmt.Sprintf("badreg(%d)", r)
217}
218
219func DRconv(a int) string {
220	if a >= C_NONE && a <= C_NCLASS {
221		return cnames7[a]
222	}
223	return "C_??"
224}
225
226func rlconv(list int64) string {
227	str := ""
228
229	// ARM64 register list follows ARM64 instruction decode schema
230	// | 31 | 30 | ... | 15 - 12 | 11 - 10 | ... |
231	// +----+----+-----+---------+---------+-----+
232	// |    | Q  | ... | opcode  |   size  | ... |
233
234	firstReg := int(list & 31)
235	opcode := (list >> 12) & 15
236	var regCnt int
237	var t string
238	switch opcode {
239	case 0x7:
240		regCnt = 1
241	case 0xa:
242		regCnt = 2
243	case 0x6:
244		regCnt = 3
245	case 0x2:
246		regCnt = 4
247	default:
248		regCnt = -1
249	}
250	// Q:size
251	arng := ((list>>30)&1)<<2 | (list>>10)&3
252	switch arng {
253	case 0:
254		t = "B8"
255	case 4:
256		t = "B16"
257	case 1:
258		t = "H4"
259	case 5:
260		t = "H8"
261	case 2:
262		t = "S2"
263	case 6:
264		t = "S4"
265	case 3:
266		t = "D1"
267	case 7:
268		t = "D2"
269	}
270	for i := 0; i < regCnt; i++ {
271		if str == "" {
272			str += "["
273		} else {
274			str += ","
275		}
276		str += fmt.Sprintf("V%d.", (firstReg+i)&31)
277		str += t
278	}
279	str += "]"
280	return str
281}
282
283func regname(r int) string {
284	if r&31 == 31 {
285		return "ZR"
286	}
287	return fmt.Sprintf("R%d", r&31)
288}
289