1
2
3
4
5
6
7
8
9 package arch
10
11 import (
12 "cmd/internal/obj"
13 "cmd/internal/obj/arm64"
14 "errors"
15 )
16
17 var arm64LS = map[string]uint8{
18 "P": arm64.C_XPOST,
19 "W": arm64.C_XPRE,
20 }
21
22 var arm64Jump = map[string]bool{
23 "B": true,
24 "BL": true,
25 "BEQ": true,
26 "BNE": true,
27 "BCS": true,
28 "BHS": true,
29 "BCC": true,
30 "BLO": true,
31 "BMI": true,
32 "BPL": true,
33 "BVS": true,
34 "BVC": true,
35 "BHI": true,
36 "BLS": true,
37 "BGE": true,
38 "BLT": true,
39 "BGT": true,
40 "BLE": true,
41 "CALL": true,
42 "CBZ": true,
43 "CBZW": true,
44 "CBNZ": true,
45 "CBNZW": true,
46 "JMP": true,
47 "TBNZ": true,
48 "TBZ": true,
49
50
51
52 "ADR": true,
53 "ADRP": true,
54 }
55
56 func jumpArm64(word string) bool {
57 return arm64Jump[word]
58 }
59
60 var arm64SpecialOperand map[string]arm64.SpecialOperand
61
62
63 func ARM64SpecialOperand(name string) arm64.SpecialOperand {
64 if arm64SpecialOperand == nil {
65
66 arm64SpecialOperand = map[string]arm64.SpecialOperand{}
67 for opd := arm64.SPOP_BEGIN; opd < arm64.SPOP_END; opd++ {
68 arm64SpecialOperand[opd.String()] = opd
69 }
70
71
72 specialMapping := map[string]arm64.SpecialOperand{
73
74 "CS": arm64.SPOP_HS,
75 "CC": arm64.SPOP_LO,
76 }
77 for s, opd := range specialMapping {
78 arm64SpecialOperand[s] = opd
79 }
80 }
81 if opd, ok := arm64SpecialOperand[name]; ok {
82 return opd
83 }
84 return arm64.SPOP_END
85 }
86
87
88
89 func IsARM64ADR(op obj.As) bool {
90 switch op {
91 case arm64.AADR, arm64.AADRP:
92 return true
93 }
94 return false
95 }
96
97
98
99 func IsARM64CMP(op obj.As) bool {
100 switch op {
101 case arm64.ACMN, arm64.ACMP, arm64.ATST,
102 arm64.ACMNW, arm64.ACMPW, arm64.ATSTW,
103 arm64.AFCMPS, arm64.AFCMPD,
104 arm64.AFCMPES, arm64.AFCMPED:
105 return true
106 }
107 return false
108 }
109
110
111
112
113 func IsARM64STLXR(op obj.As) bool {
114 switch op {
115 case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR,
116 arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR,
117 arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW:
118 return true
119 }
120
121 return arm64.IsAtomicInstruction(op)
122 }
123
124
125
126
127 func IsARM64TBL(op obj.As) bool {
128 switch op {
129 case arm64.AVTBL, arm64.AVTBX, arm64.AVMOVQ:
130 return true
131 }
132 return false
133 }
134
135
136
137
138 func IsARM64CASP(op obj.As) bool {
139 switch op {
140 case arm64.ACASPD, arm64.ACASPW:
141 return true
142 }
143 return false
144 }
145
146
147
148
149 func ARM64Suffix(prog *obj.Prog, cond string) bool {
150 if cond == "" {
151 return true
152 }
153 bits, ok := parseARM64Suffix(cond)
154 if !ok {
155 return false
156 }
157 prog.Scond = bits
158 return true
159 }
160
161
162
163
164 func parseARM64Suffix(cond string) (uint8, bool) {
165 if cond == "" {
166 return 0, true
167 }
168 return parseARMCondition(cond, arm64LS, nil)
169 }
170
171 func arm64RegisterNumber(name string, n int16) (int16, bool) {
172 switch name {
173 case "F":
174 if 0 <= n && n <= 31 {
175 return arm64.REG_F0 + n, true
176 }
177 case "R":
178 if 0 <= n && n <= 30 {
179 return arm64.REG_R0 + n, true
180 }
181 case "V":
182 if 0 <= n && n <= 31 {
183 return arm64.REG_V0 + n, true
184 }
185 }
186 return 0, false
187 }
188
189
190 func ARM64RegisterShift(reg, op, count int16) (int64, error) {
191
192 if reg > arm64.REG_R31 || reg < arm64.REG_R0 {
193 return 0, errors.New("invalid register for shift operation")
194 }
195 return int64(reg&31)<<16 | int64(op)<<22 | int64(uint16(count)), nil
196 }
197
198
199 func ARM64RegisterArrangement(reg int16, name, arng string) (int64, error) {
200 var curQ, curSize uint16
201 if name[0] != 'V' {
202 return 0, errors.New("expect V0 through V31; found: " + name)
203 }
204 if reg < 0 {
205 return 0, errors.New("invalid register number: " + name)
206 }
207 switch arng {
208 case "B8":
209 curSize = 0
210 curQ = 0
211 case "B16":
212 curSize = 0
213 curQ = 1
214 case "H4":
215 curSize = 1
216 curQ = 0
217 case "H8":
218 curSize = 1
219 curQ = 1
220 case "S2":
221 curSize = 2
222 curQ = 0
223 case "S4":
224 curSize = 2
225 curQ = 1
226 case "D1":
227 curSize = 3
228 curQ = 0
229 case "D2":
230 curSize = 3
231 curQ = 1
232 default:
233 return 0, errors.New("invalid arrangement in ARM64 register list")
234 }
235 return (int64(curQ) & 1 << 30) | (int64(curSize&3) << 10), nil
236 }
237
238
239 func ARM64RegisterListOffset(firstReg, regCnt int, arrangement int64) (int64, error) {
240 offset := int64(firstReg)
241 switch regCnt {
242 case 1:
243 offset |= 0x7 << 12
244 case 2:
245 offset |= 0xa << 12
246 case 3:
247 offset |= 0x6 << 12
248 case 4:
249 offset |= 0x2 << 12
250 default:
251 return 0, errors.New("invalid register numbers in ARM64 register list")
252 }
253 offset |= arrangement
254
255
256 offset |= 1 << 60
257 return offset, nil
258 }
259
View as plain text