blob: 4a3cfa778a453f010bce7dd34f4a623e6d586511 [file] [log] [blame]
Claudio Fontana4a136e02013-06-12 16:20:22 +01001/*
2 * Initial TCG Implementation for aarch64
3 *
4 * Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
5 * Written by Claudio Fontana
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or
8 * (at your option) any later version.
9 *
10 * See the COPYING file in the top-level directory for details.
11 */
12
Richard Henderson55129952017-07-26 00:29:49 -070013#include "tcg-pool.inc.c"
Claudio Fontana4a136e02013-06-12 16:20:22 +010014#include "qemu/bitops.h"
15
Richard Henderson7763ffa2013-08-15 11:11:00 -070016/* We're going to re-use TCGType in setting of the SF bit, which controls
17 the size of the operation performed. If we know the values match, it
18 makes things much cleaner. */
19QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1);
20
Aurelien Jarno8d8fdba2016-04-21 10:48:50 +020021#ifdef CONFIG_DEBUG_TCG
Claudio Fontana4a136e02013-06-12 16:20:22 +010022static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
Richard Henderson14e4c1e2017-09-11 22:09:28 -070023 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
24 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
25 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
26 "x24", "x25", "x26", "x27", "x28", "fp", "x30", "sp",
27
28 "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
29 "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
30 "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
31 "v24", "v25", "v26", "v27", "v28", "fp", "v30", "v31",
Claudio Fontana4a136e02013-06-12 16:20:22 +010032};
Aurelien Jarno8d8fdba2016-04-21 10:48:50 +020033#endif /* CONFIG_DEBUG_TCG */
Claudio Fontana4a136e02013-06-12 16:20:22 +010034
35static const int tcg_target_reg_alloc_order[] = {
36 TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23,
37 TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27,
Laurent Vivierb76f21a2015-08-24 14:53:54 +020038 TCG_REG_X28, /* we will reserve this for guest_base if configured */
Claudio Fontana4a136e02013-06-12 16:20:22 +010039
Richard Hendersond82b78e2013-08-15 12:54:28 -070040 TCG_REG_X8, TCG_REG_X9, TCG_REG_X10, TCG_REG_X11,
41 TCG_REG_X12, TCG_REG_X13, TCG_REG_X14, TCG_REG_X15,
Claudio Fontana4a136e02013-06-12 16:20:22 +010042 TCG_REG_X16, TCG_REG_X17,
43
Claudio Fontana4a136e02013-06-12 16:20:22 +010044 TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
45 TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7,
46
Richard Hendersond82b78e2013-08-15 12:54:28 -070047 /* X18 reserved by system */
48 /* X19 reserved for AREG0 */
49 /* X29 reserved as fp */
50 /* X30 reserved as temporary */
Richard Henderson14e4c1e2017-09-11 22:09:28 -070051
52 TCG_REG_V0, TCG_REG_V1, TCG_REG_V2, TCG_REG_V3,
53 TCG_REG_V4, TCG_REG_V5, TCG_REG_V6, TCG_REG_V7,
54 /* V8 - V15 are call-saved, and skipped. */
55 TCG_REG_V16, TCG_REG_V17, TCG_REG_V18, TCG_REG_V19,
56 TCG_REG_V20, TCG_REG_V21, TCG_REG_V22, TCG_REG_V23,
57 TCG_REG_V24, TCG_REG_V25, TCG_REG_V26, TCG_REG_V27,
58 TCG_REG_V28, TCG_REG_V29, TCG_REG_V30, TCG_REG_V31,
Claudio Fontana4a136e02013-06-12 16:20:22 +010059};
60
61static const int tcg_target_call_iarg_regs[8] = {
62 TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
63 TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7
64};
65static const int tcg_target_call_oarg_regs[1] = {
66 TCG_REG_X0
67};
68
Richard Hendersond82b78e2013-08-15 12:54:28 -070069#define TCG_REG_TMP TCG_REG_X30
Richard Henderson14e4c1e2017-09-11 22:09:28 -070070#define TCG_VEC_TMP TCG_REG_V31
Claudio Fontana4a136e02013-06-12 16:20:22 +010071
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +010072#ifndef CONFIG_SOFTMMU
Richard Henderson352bcb02015-09-01 15:58:02 -040073/* Note that XZR cannot be encoded in the address base register slot,
74 as that actaully encodes SP. So if we need to zero-extend the guest
75 address, via the address index register slot, we need to load even
76 a zero guest base into a register. */
77#define USE_GUEST_BASE (guest_base != 0 || TARGET_LONG_BITS == 32)
Laurent Vivier4cbea592015-08-24 01:42:07 +020078#define TCG_REG_GUEST_BASE TCG_REG_X28
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +010079#endif
80
Richard Henderson214bfe82018-11-30 12:44:53 -080081static inline bool reloc_pc26(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
Claudio Fontana4a136e02013-06-12 16:20:22 +010082{
Richard Henderson8587c302014-04-28 12:02:31 -070083 ptrdiff_t offset = target - code_ptr;
Richard Henderson214bfe82018-11-30 12:44:53 -080084 if (offset == sextract64(offset, 0, 26)) {
85 /* read instruction, mask away previous PC_REL26 parameter contents,
86 set the proper offset, then write back the instruction. */
87 *code_ptr = deposit32(*code_ptr, 0, 26, offset);
88 return true;
89 }
90 return false;
Claudio Fontana4a136e02013-06-12 16:20:22 +010091}
92
Richard Henderson214bfe82018-11-30 12:44:53 -080093static inline bool reloc_pc19(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
Claudio Fontana4a136e02013-06-12 16:20:22 +010094{
Richard Henderson8587c302014-04-28 12:02:31 -070095 ptrdiff_t offset = target - code_ptr;
Richard Henderson214bfe82018-11-30 12:44:53 -080096 if (offset == sextract64(offset, 0, 19)) {
97 *code_ptr = deposit32(*code_ptr, 5, 19, offset);
98 return true;
99 }
100 return false;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100101}
102
Richard Henderson6ac17782018-11-30 11:52:48 -0800103static inline bool patch_reloc(tcg_insn_unit *code_ptr, int type,
Richard Henderson2ba7fae22013-08-20 15:30:10 -0700104 intptr_t value, intptr_t addend)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100105{
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200106 tcg_debug_assert(addend == 0);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100107 switch (type) {
108 case R_AARCH64_JUMP26:
109 case R_AARCH64_CALL26:
Richard Henderson214bfe82018-11-30 12:44:53 -0800110 return reloc_pc26(code_ptr, (tcg_insn_unit *)value);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100111 case R_AARCH64_CONDBR19:
Richard Henderson214bfe82018-11-30 12:44:53 -0800112 return reloc_pc19(code_ptr, (tcg_insn_unit *)value);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100113 default:
Richard Henderson214bfe82018-11-30 12:44:53 -0800114 g_assert_not_reached();
Claudio Fontana4a136e02013-06-12 16:20:22 +0100115 }
116}
117
Richard Henderson170bf932014-03-30 21:26:34 -0700118#define TCG_CT_CONST_AIMM 0x100
119#define TCG_CT_CONST_LIMM 0x200
120#define TCG_CT_CONST_ZERO 0x400
121#define TCG_CT_CONST_MONE 0x800
Richard Henderson90f1cd92013-08-14 09:56:14 -0700122
Claudio Fontana4a136e02013-06-12 16:20:22 +0100123/* parse target specific constraints */
Richard Henderson069ea732016-11-18 11:50:59 +0100124static const char *target_parse_constraint(TCGArgConstraint *ct,
125 const char *ct_str, TCGType type)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100126{
Richard Henderson069ea732016-11-18 11:50:59 +0100127 switch (*ct_str++) {
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700128 case 'r': /* general registers */
Claudio Fontana4a136e02013-06-12 16:20:22 +0100129 ct->ct |= TCG_CT_REG;
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700130 ct->u.regs |= 0xffffffffu;
131 break;
132 case 'w': /* advsimd registers */
133 ct->ct |= TCG_CT_REG;
134 ct->u.regs |= 0xffffffff00000000ull;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100135 break;
136 case 'l': /* qemu_ld / qemu_st address, data_reg */
137 ct->ct |= TCG_CT_REG;
Richard Hendersonf46934d2017-09-11 12:44:30 -0700138 ct->u.regs = 0xffffffffu;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100139#ifdef CONFIG_SOFTMMU
140 /* x0 and x1 will be overwritten when reading the tlb entry,
141 and x2, and x3 for helper args, better to avoid using them. */
142 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X0);
143 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X1);
144 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X2);
145 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3);
146#endif
147 break;
Richard Henderson90f1cd92013-08-14 09:56:14 -0700148 case 'A': /* Valid for arithmetic immediate (positive or negative). */
149 ct->ct |= TCG_CT_CONST_AIMM;
150 break;
Richard Hendersone029f292013-08-14 11:27:03 -0700151 case 'L': /* Valid for logical immediate. */
152 ct->ct |= TCG_CT_CONST_LIMM;
153 break;
Richard Hendersonc6e929e2013-08-14 13:30:07 -0700154 case 'M': /* minus one */
155 ct->ct |= TCG_CT_CONST_MONE;
156 break;
Richard Henderson04ce3972013-08-09 23:58:19 -0400157 case 'Z': /* zero */
158 ct->ct |= TCG_CT_CONST_ZERO;
159 break;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100160 default:
Richard Henderson069ea732016-11-18 11:50:59 +0100161 return NULL;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100162 }
Richard Henderson069ea732016-11-18 11:50:59 +0100163 return ct_str;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100164}
165
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700166/* Match a constant valid for addition (12-bit, optionally shifted). */
Richard Henderson90f1cd92013-08-14 09:56:14 -0700167static inline bool is_aimm(uint64_t val)
168{
169 return (val & ~0xfff) == 0 || (val & ~0xfff000) == 0;
170}
171
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700172/* Match a constant valid for logical operations. */
Richard Hendersone029f292013-08-14 11:27:03 -0700173static inline bool is_limm(uint64_t val)
174{
175 /* Taking a simplified view of the logical immediates for now, ignoring
176 the replication that can happen across the field. Match bit patterns
177 of the forms
178 0....01....1
179 0..01..10..0
180 and their inverses. */
181
182 /* Make things easier below, by testing the form with msb clear. */
183 if ((int64_t)val < 0) {
184 val = ~val;
185 }
186 if (val == 0) {
187 return false;
188 }
189 val += val & -val;
190 return (val & (val - 1)) == 0;
191}
192
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700193/* Match a constant that is valid for vectors. */
194static bool is_fimm(uint64_t v64, int *op, int *cmode, int *imm8)
195{
196 int i;
197
198 *op = 0;
199 /* Match replication across 8 bits. */
200 if (v64 == dup_const(MO_8, v64)) {
201 *cmode = 0xe;
202 *imm8 = v64 & 0xff;
203 return true;
204 }
205 /* Match replication across 16 bits. */
206 if (v64 == dup_const(MO_16, v64)) {
207 uint16_t v16 = v64;
208
209 if (v16 == (v16 & 0xff)) {
210 *cmode = 0x8;
211 *imm8 = v16 & 0xff;
212 return true;
213 } else if (v16 == (v16 & 0xff00)) {
214 *cmode = 0xa;
215 *imm8 = v16 >> 8;
216 return true;
217 }
218 }
219 /* Match replication across 32 bits. */
220 if (v64 == dup_const(MO_32, v64)) {
221 uint32_t v32 = v64;
222
223 if (v32 == (v32 & 0xff)) {
224 *cmode = 0x0;
225 *imm8 = v32 & 0xff;
226 return true;
227 } else if (v32 == (v32 & 0xff00)) {
228 *cmode = 0x2;
229 *imm8 = (v32 >> 8) & 0xff;
230 return true;
231 } else if (v32 == (v32 & 0xff0000)) {
232 *cmode = 0x4;
233 *imm8 = (v32 >> 16) & 0xff;
234 return true;
235 } else if (v32 == (v32 & 0xff000000)) {
236 *cmode = 0x6;
237 *imm8 = v32 >> 24;
238 return true;
239 } else if ((v32 & 0xffff00ff) == 0xff) {
240 *cmode = 0xc;
241 *imm8 = (v32 >> 8) & 0xff;
242 return true;
243 } else if ((v32 & 0xff00ffff) == 0xffff) {
244 *cmode = 0xd;
245 *imm8 = (v32 >> 16) & 0xff;
246 return true;
247 }
248 /* Match forms of a float32. */
249 if (extract32(v32, 0, 19) == 0
250 && (extract32(v32, 25, 6) == 0x20
251 || extract32(v32, 25, 6) == 0x1f)) {
252 *cmode = 0xf;
253 *imm8 = (extract32(v32, 31, 1) << 7)
254 | (extract32(v32, 25, 1) << 6)
255 | extract32(v32, 19, 6);
256 return true;
257 }
258 }
259 /* Match forms of a float64. */
260 if (extract64(v64, 0, 48) == 0
261 && (extract64(v64, 54, 9) == 0x100
262 || extract64(v64, 54, 9) == 0x0ff)) {
263 *cmode = 0xf;
264 *op = 1;
265 *imm8 = (extract64(v64, 63, 1) << 7)
266 | (extract64(v64, 54, 1) << 6)
267 | extract64(v64, 48, 6);
268 return true;
269 }
270 /* Match bytes of 0x00 and 0xff. */
271 for (i = 0; i < 64; i += 8) {
272 uint64_t byte = extract64(v64, i, 8);
273 if (byte != 0 && byte != 0xff) {
274 break;
275 }
276 }
277 if (i == 64) {
278 *cmode = 0xe;
279 *op = 1;
280 *imm8 = (extract64(v64, 0, 1) << 0)
281 | (extract64(v64, 8, 1) << 1)
282 | (extract64(v64, 16, 1) << 2)
283 | (extract64(v64, 24, 1) << 3)
284 | (extract64(v64, 32, 1) << 4)
285 | (extract64(v64, 40, 1) << 5)
286 | (extract64(v64, 48, 1) << 6)
287 | (extract64(v64, 56, 1) << 7);
288 return true;
289 }
290 return false;
291}
292
Richard Hendersonf6c6afc2014-03-30 21:22:11 -0700293static int tcg_target_const_match(tcg_target_long val, TCGType type,
Richard Henderson90f1cd92013-08-14 09:56:14 -0700294 const TCGArgConstraint *arg_ct)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100295{
296 int ct = arg_ct->ct;
297
298 if (ct & TCG_CT_CONST) {
299 return 1;
300 }
Richard Henderson170bf932014-03-30 21:26:34 -0700301 if (type == TCG_TYPE_I32) {
Richard Henderson90f1cd92013-08-14 09:56:14 -0700302 val = (int32_t)val;
303 }
304 if ((ct & TCG_CT_CONST_AIMM) && (is_aimm(val) || is_aimm(-val))) {
305 return 1;
306 }
Richard Hendersone029f292013-08-14 11:27:03 -0700307 if ((ct & TCG_CT_CONST_LIMM) && is_limm(val)) {
308 return 1;
309 }
Richard Henderson04ce3972013-08-09 23:58:19 -0400310 if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
311 return 1;
312 }
Richard Hendersonc6e929e2013-08-14 13:30:07 -0700313 if ((ct & TCG_CT_CONST_MONE) && val == -1) {
314 return 1;
315 }
Claudio Fontana4a136e02013-06-12 16:20:22 +0100316
317 return 0;
318}
319
320enum aarch64_cond_code {
321 COND_EQ = 0x0,
322 COND_NE = 0x1,
323 COND_CS = 0x2, /* Unsigned greater or equal */
324 COND_HS = COND_CS, /* ALIAS greater or equal */
325 COND_CC = 0x3, /* Unsigned less than */
326 COND_LO = COND_CC, /* ALIAS Lower */
327 COND_MI = 0x4, /* Negative */
328 COND_PL = 0x5, /* Zero or greater */
329 COND_VS = 0x6, /* Overflow */
330 COND_VC = 0x7, /* No overflow */
331 COND_HI = 0x8, /* Unsigned greater than */
332 COND_LS = 0x9, /* Unsigned less or equal */
333 COND_GE = 0xa,
334 COND_LT = 0xb,
335 COND_GT = 0xc,
336 COND_LE = 0xd,
337 COND_AL = 0xe,
338 COND_NV = 0xf, /* behaves like COND_AL here */
339};
340
341static const enum aarch64_cond_code tcg_cond_to_aarch64[] = {
342 [TCG_COND_EQ] = COND_EQ,
343 [TCG_COND_NE] = COND_NE,
344 [TCG_COND_LT] = COND_LT,
345 [TCG_COND_GE] = COND_GE,
346 [TCG_COND_LE] = COND_LE,
347 [TCG_COND_GT] = COND_GT,
348 /* unsigned */
349 [TCG_COND_LTU] = COND_LO,
350 [TCG_COND_GTU] = COND_HI,
351 [TCG_COND_GEU] = COND_HS,
352 [TCG_COND_LEU] = COND_LS,
353};
354
Richard Henderson3d4299f2014-03-03 17:11:49 -0800355typedef enum {
356 LDST_ST = 0, /* store */
357 LDST_LD = 1, /* load */
358 LDST_LD_S_X = 2, /* load and sign-extend into Xt */
359 LDST_LD_S_W = 3, /* load and sign-extend into Wt */
360} AArch64LdstType;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100361
Richard Henderson50573c62013-08-13 12:10:08 -0700362/* We encode the format of the insn into the beginning of the name, so that
363 we can have the preprocessor help "typecheck" the insn vs the output
364 function. Arm didn't provide us with nice names for the formats, so we
365 use the section number of the architecture reference manual in which the
366 instruction group is described. */
367typedef enum {
Richard Henderson3d9e69a2014-02-27 19:55:30 -0500368 /* Compare and branch (immediate). */
369 I3201_CBZ = 0x34000000,
370 I3201_CBNZ = 0x35000000,
371
Richard Henderson81d8a5e2013-08-14 20:05:51 -0700372 /* Conditional branch (immediate). */
373 I3202_B_C = 0x54000000,
374
375 /* Unconditional branch (immediate). */
376 I3206_B = 0x14000000,
377 I3206_BL = 0x94000000,
378
379 /* Unconditional branch (register). */
380 I3207_BR = 0xd61f0000,
381 I3207_BLR = 0xd63f0000,
382 I3207_RET = 0xd65f0000,
383
Pranith Kumar2acee8b2017-06-30 10:36:14 -0400384 /* Load literal for loading the address at pc-relative offset */
385 I3305_LDR = 0x58000000,
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700386 I3305_LDR_v64 = 0x5c000000,
387 I3305_LDR_v128 = 0x9c000000,
388
Richard Henderson3d4299f2014-03-03 17:11:49 -0800389 /* Load/store register. Described here as 3.3.12, but the helper
390 that emits them can transform to 3.3.10 or 3.3.13. */
391 I3312_STRB = 0x38000000 | LDST_ST << 22 | MO_8 << 30,
392 I3312_STRH = 0x38000000 | LDST_ST << 22 | MO_16 << 30,
393 I3312_STRW = 0x38000000 | LDST_ST << 22 | MO_32 << 30,
394 I3312_STRX = 0x38000000 | LDST_ST << 22 | MO_64 << 30,
395
396 I3312_LDRB = 0x38000000 | LDST_LD << 22 | MO_8 << 30,
397 I3312_LDRH = 0x38000000 | LDST_LD << 22 | MO_16 << 30,
398 I3312_LDRW = 0x38000000 | LDST_LD << 22 | MO_32 << 30,
399 I3312_LDRX = 0x38000000 | LDST_LD << 22 | MO_64 << 30,
400
401 I3312_LDRSBW = 0x38000000 | LDST_LD_S_W << 22 | MO_8 << 30,
402 I3312_LDRSHW = 0x38000000 | LDST_LD_S_W << 22 | MO_16 << 30,
403
404 I3312_LDRSBX = 0x38000000 | LDST_LD_S_X << 22 | MO_8 << 30,
405 I3312_LDRSHX = 0x38000000 | LDST_LD_S_X << 22 | MO_16 << 30,
406 I3312_LDRSWX = 0x38000000 | LDST_LD_S_X << 22 | MO_32 << 30,
407
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700408 I3312_LDRVS = 0x3c000000 | LDST_LD << 22 | MO_32 << 30,
409 I3312_STRVS = 0x3c000000 | LDST_ST << 22 | MO_32 << 30,
410
411 I3312_LDRVD = 0x3c000000 | LDST_LD << 22 | MO_64 << 30,
412 I3312_STRVD = 0x3c000000 | LDST_ST << 22 | MO_64 << 30,
413
414 I3312_LDRVQ = 0x3c000000 | 3 << 22 | 0 << 30,
415 I3312_STRVQ = 0x3c000000 | 2 << 22 | 0 << 30,
416
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +0200417 I3312_TO_I3310 = 0x00200800,
Richard Henderson3d4299f2014-03-03 17:11:49 -0800418 I3312_TO_I3313 = 0x01000000,
419
Richard Henderson95f72aa2013-08-15 13:34:47 -0700420 /* Load/store register pair instructions. */
421 I3314_LDP = 0x28400000,
422 I3314_STP = 0x28000000,
423
Richard Henderson096c46c2013-08-13 14:37:08 -0700424 /* Add/subtract immediate instructions. */
425 I3401_ADDI = 0x11000000,
426 I3401_ADDSI = 0x31000000,
427 I3401_SUBI = 0x51000000,
428 I3401_SUBSI = 0x71000000,
429
Richard Hendersonb3c56df2013-08-14 13:05:07 -0700430 /* Bitfield instructions. */
431 I3402_BFM = 0x33000000,
432 I3402_SBFM = 0x13000000,
433 I3402_UBFM = 0x53000000,
434
435 /* Extract instruction. */
436 I3403_EXTR = 0x13800000,
437
Richard Hendersone029f292013-08-14 11:27:03 -0700438 /* Logical immediate instructions. */
439 I3404_ANDI = 0x12000000,
440 I3404_ORRI = 0x32000000,
441 I3404_EORI = 0x52000000,
442
Richard Henderson582ab772013-08-14 15:57:36 -0700443 /* Move wide immediate instructions. */
444 I3405_MOVN = 0x12800000,
445 I3405_MOVZ = 0x52800000,
446 I3405_MOVK = 0x72800000,
447
Richard Hendersonc6e310d2013-08-10 15:28:48 -0400448 /* PC relative addressing instructions. */
449 I3406_ADR = 0x10000000,
450 I3406_ADRP = 0x90000000,
451
Richard Henderson50573c62013-08-13 12:10:08 -0700452 /* Add/subtract shifted register instructions (without a shift). */
453 I3502_ADD = 0x0b000000,
454 I3502_ADDS = 0x2b000000,
455 I3502_SUB = 0x4b000000,
456 I3502_SUBS = 0x6b000000,
457
458 /* Add/subtract shifted register instructions (with a shift). */
459 I3502S_ADD_LSL = I3502_ADD,
460
Richard Hendersonc6e929e2013-08-14 13:30:07 -0700461 /* Add/subtract with carry instructions. */
462 I3503_ADC = 0x1a000000,
463 I3503_SBC = 0x5a000000,
464
Richard Henderson04ce3972013-08-09 23:58:19 -0400465 /* Conditional select instructions. */
466 I3506_CSEL = 0x1a800000,
467 I3506_CSINC = 0x1a800400,
Richard Henderson53c76c12016-11-16 14:03:28 +0100468 I3506_CSINV = 0x5a800000,
469 I3506_CSNEG = 0x5a800400,
Richard Henderson04ce3972013-08-09 23:58:19 -0400470
Richard Hendersonedd88242014-03-03 16:21:27 -0800471 /* Data-processing (1 source) instructions. */
Richard Henderson53c76c12016-11-16 14:03:28 +0100472 I3507_CLZ = 0x5ac01000,
473 I3507_RBIT = 0x5ac00000,
Richard Hendersonedd88242014-03-03 16:21:27 -0800474 I3507_REV16 = 0x5ac00400,
475 I3507_REV32 = 0x5ac00800,
476 I3507_REV64 = 0x5ac00c00,
477
Richard Hendersondf9351e2013-08-13 13:49:17 -0700478 /* Data-processing (2 source) instructions. */
479 I3508_LSLV = 0x1ac02000,
480 I3508_LSRV = 0x1ac02400,
481 I3508_ASRV = 0x1ac02800,
482 I3508_RORV = 0x1ac02c00,
Richard Henderson1fcc9dd2013-08-14 15:03:27 -0700483 I3508_SMULH = 0x9b407c00,
484 I3508_UMULH = 0x9bc07c00,
Richard Henderson8678b712013-08-14 15:29:18 -0700485 I3508_UDIV = 0x1ac00800,
486 I3508_SDIV = 0x1ac00c00,
487
488 /* Data-processing (3 source) instructions. */
489 I3509_MADD = 0x1b000000,
490 I3509_MSUB = 0x1b008000,
Richard Hendersondf9351e2013-08-13 13:49:17 -0700491
Richard Henderson50573c62013-08-13 12:10:08 -0700492 /* Logical shifted register instructions (without a shift). */
493 I3510_AND = 0x0a000000,
Richard Henderson14b155d2013-08-09 23:15:44 -0400494 I3510_BIC = 0x0a200000,
Richard Henderson50573c62013-08-13 12:10:08 -0700495 I3510_ORR = 0x2a000000,
Richard Henderson14b155d2013-08-09 23:15:44 -0400496 I3510_ORN = 0x2a200000,
Richard Henderson50573c62013-08-13 12:10:08 -0700497 I3510_EOR = 0x4a000000,
Richard Henderson14b155d2013-08-09 23:15:44 -0400498 I3510_EON = 0x4a200000,
Richard Henderson50573c62013-08-13 12:10:08 -0700499 I3510_ANDS = 0x6a000000,
Pranith Kumarc7a59c22016-07-14 16:20:15 -0400500
Richard Hendersonf7bcd962018-12-25 22:33:50 +0000501 /* Logical shifted register instructions (with a shift). */
502 I3502S_AND_LSR = I3510_AND | (1 << 22),
503
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700504 /* AdvSIMD copy */
505 I3605_DUP = 0x0e000400,
506 I3605_INS = 0x4e001c00,
507 I3605_UMOV = 0x0e003c00,
508
509 /* AdvSIMD modified immediate */
510 I3606_MOVI = 0x0f000400,
511
512 /* AdvSIMD shift by immediate */
513 I3614_SSHR = 0x0f000400,
514 I3614_SSRA = 0x0f001400,
515 I3614_SHL = 0x0f005400,
516 I3614_USHR = 0x2f000400,
517 I3614_USRA = 0x2f001400,
518
519 /* AdvSIMD three same. */
520 I3616_ADD = 0x0e208400,
521 I3616_AND = 0x0e201c00,
522 I3616_BIC = 0x0e601c00,
523 I3616_EOR = 0x2e201c00,
524 I3616_MUL = 0x0e209c00,
525 I3616_ORR = 0x0ea01c00,
526 I3616_ORN = 0x0ee01c00,
527 I3616_SUB = 0x2e208400,
528 I3616_CMGT = 0x0e203400,
529 I3616_CMGE = 0x0e203c00,
530 I3616_CMTST = 0x0e208c00,
531 I3616_CMHI = 0x2e203400,
532 I3616_CMHS = 0x2e203c00,
533 I3616_CMEQ = 0x2e208c00,
Richard Henderson93f332a2018-12-18 07:27:06 +0000534 I3616_SMAX = 0x0e206400,
535 I3616_SMIN = 0x0e206c00,
Richard Hendersond32648d2018-12-18 07:14:23 +0000536 I3616_SQADD = 0x0e200c00,
537 I3616_SQSUB = 0x0e202c00,
Richard Henderson93f332a2018-12-18 07:27:06 +0000538 I3616_UMAX = 0x2e206400,
539 I3616_UMIN = 0x2e206c00,
Richard Hendersond32648d2018-12-18 07:14:23 +0000540 I3616_UQADD = 0x2e200c00,
541 I3616_UQSUB = 0x2e202c00,
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700542
543 /* AdvSIMD two-reg misc. */
544 I3617_CMGT0 = 0x0e208800,
545 I3617_CMEQ0 = 0x0e209800,
546 I3617_CMLT0 = 0x0e20a800,
547 I3617_CMGE0 = 0x2e208800,
548 I3617_CMLE0 = 0x2e20a800,
549 I3617_NOT = 0x2e205800,
550 I3617_NEG = 0x2e20b800,
551
Pranith Kumarc7a59c22016-07-14 16:20:15 -0400552 /* System instructions. */
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700553 NOP = 0xd503201f,
Pranith Kumarc7a59c22016-07-14 16:20:15 -0400554 DMB_ISH = 0xd50338bf,
555 DMB_LD = 0x00000100,
556 DMB_ST = 0x00000200,
Richard Henderson50573c62013-08-13 12:10:08 -0700557} AArch64Insn;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100558
Claudio Fontana4a136e02013-06-12 16:20:22 +0100559static inline uint32_t tcg_in32(TCGContext *s)
560{
561 uint32_t v = *(uint32_t *)s->code_ptr;
562 return v;
563}
564
Richard Henderson50573c62013-08-13 12:10:08 -0700565/* Emit an opcode with "type-checking" of the format. */
566#define tcg_out_insn(S, FMT, OP, ...) \
567 glue(tcg_out_insn_,FMT)(S, glue(glue(glue(I,FMT),_),OP), ## __VA_ARGS__)
568
Pranith Kumar2acee8b2017-06-30 10:36:14 -0400569static void tcg_out_insn_3305(TCGContext *s, AArch64Insn insn, int imm19, TCGReg rt)
570{
571 tcg_out32(s, insn | (imm19 & 0x7ffff) << 5 | rt);
572}
573
Richard Henderson3d9e69a2014-02-27 19:55:30 -0500574static void tcg_out_insn_3201(TCGContext *s, AArch64Insn insn, TCGType ext,
575 TCGReg rt, int imm19)
576{
577 tcg_out32(s, insn | ext << 31 | (imm19 & 0x7ffff) << 5 | rt);
578}
579
Richard Henderson81d8a5e2013-08-14 20:05:51 -0700580static void tcg_out_insn_3202(TCGContext *s, AArch64Insn insn,
581 TCGCond c, int imm19)
582{
583 tcg_out32(s, insn | tcg_cond_to_aarch64[c] | (imm19 & 0x7ffff) << 5);
584}
585
586static void tcg_out_insn_3206(TCGContext *s, AArch64Insn insn, int imm26)
587{
588 tcg_out32(s, insn | (imm26 & 0x03ffffff));
589}
590
591static void tcg_out_insn_3207(TCGContext *s, AArch64Insn insn, TCGReg rn)
592{
593 tcg_out32(s, insn | rn << 5);
594}
595
Richard Henderson95f72aa2013-08-15 13:34:47 -0700596static void tcg_out_insn_3314(TCGContext *s, AArch64Insn insn,
597 TCGReg r1, TCGReg r2, TCGReg rn,
598 tcg_target_long ofs, bool pre, bool w)
599{
600 insn |= 1u << 31; /* ext */
601 insn |= pre << 24;
602 insn |= w << 23;
603
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200604 tcg_debug_assert(ofs >= -0x200 && ofs < 0x200 && (ofs & 7) == 0);
Richard Henderson95f72aa2013-08-15 13:34:47 -0700605 insn |= (ofs & (0x7f << 3)) << (15 - 3);
606
607 tcg_out32(s, insn | r2 << 10 | rn << 5 | r1);
608}
609
Richard Henderson096c46c2013-08-13 14:37:08 -0700610static void tcg_out_insn_3401(TCGContext *s, AArch64Insn insn, TCGType ext,
611 TCGReg rd, TCGReg rn, uint64_t aimm)
612{
613 if (aimm > 0xfff) {
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200614 tcg_debug_assert((aimm & 0xfff) == 0);
Richard Henderson096c46c2013-08-13 14:37:08 -0700615 aimm >>= 12;
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200616 tcg_debug_assert(aimm <= 0xfff);
Richard Henderson096c46c2013-08-13 14:37:08 -0700617 aimm |= 1 << 12; /* apply LSL 12 */
618 }
619 tcg_out32(s, insn | ext << 31 | aimm << 10 | rn << 5 | rd);
620}
621
Richard Hendersone029f292013-08-14 11:27:03 -0700622/* This function can be used for both 3.4.2 (Bitfield) and 3.4.4
623 (Logical immediate). Both insn groups have N, IMMR and IMMS fields
624 that feed the DecodeBitMasks pseudo function. */
625static void tcg_out_insn_3402(TCGContext *s, AArch64Insn insn, TCGType ext,
626 TCGReg rd, TCGReg rn, int n, int immr, int imms)
627{
628 tcg_out32(s, insn | ext << 31 | n << 22 | immr << 16 | imms << 10
629 | rn << 5 | rd);
630}
631
632#define tcg_out_insn_3404 tcg_out_insn_3402
633
Richard Hendersonb3c56df2013-08-14 13:05:07 -0700634static void tcg_out_insn_3403(TCGContext *s, AArch64Insn insn, TCGType ext,
635 TCGReg rd, TCGReg rn, TCGReg rm, int imms)
636{
637 tcg_out32(s, insn | ext << 31 | ext << 22 | rm << 16 | imms << 10
638 | rn << 5 | rd);
639}
640
Richard Henderson582ab772013-08-14 15:57:36 -0700641/* This function is used for the Move (wide immediate) instruction group.
642 Note that SHIFT is a full shift count, not the 2 bit HW field. */
643static void tcg_out_insn_3405(TCGContext *s, AArch64Insn insn, TCGType ext,
644 TCGReg rd, uint16_t half, unsigned shift)
645{
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200646 tcg_debug_assert((shift & ~0x30) == 0);
Richard Henderson582ab772013-08-14 15:57:36 -0700647 tcg_out32(s, insn | ext << 31 | shift << (21 - 4) | half << 5 | rd);
648}
649
Richard Hendersonc6e310d2013-08-10 15:28:48 -0400650static void tcg_out_insn_3406(TCGContext *s, AArch64Insn insn,
651 TCGReg rd, int64_t disp)
652{
653 tcg_out32(s, insn | (disp & 3) << 29 | (disp & 0x1ffffc) << (5 - 2) | rd);
654}
655
Richard Henderson50573c62013-08-13 12:10:08 -0700656/* This function is for both 3.5.2 (Add/Subtract shifted register), for
657 the rare occasion when we actually want to supply a shift amount. */
658static inline void tcg_out_insn_3502S(TCGContext *s, AArch64Insn insn,
659 TCGType ext, TCGReg rd, TCGReg rn,
660 TCGReg rm, int imm6)
661{
662 tcg_out32(s, insn | ext << 31 | rm << 16 | imm6 << 10 | rn << 5 | rd);
663}
664
665/* This function is for 3.5.2 (Add/subtract shifted register),
666 and 3.5.10 (Logical shifted register), for the vast majorty of cases
667 when we don't want to apply a shift. Thus it can also be used for
668 3.5.3 (Add/subtract with carry) and 3.5.8 (Data processing 2 source). */
669static void tcg_out_insn_3502(TCGContext *s, AArch64Insn insn, TCGType ext,
670 TCGReg rd, TCGReg rn, TCGReg rm)
671{
672 tcg_out32(s, insn | ext << 31 | rm << 16 | rn << 5 | rd);
673}
674
675#define tcg_out_insn_3503 tcg_out_insn_3502
676#define tcg_out_insn_3508 tcg_out_insn_3502
677#define tcg_out_insn_3510 tcg_out_insn_3502
678
Richard Henderson04ce3972013-08-09 23:58:19 -0400679static void tcg_out_insn_3506(TCGContext *s, AArch64Insn insn, TCGType ext,
680 TCGReg rd, TCGReg rn, TCGReg rm, TCGCond c)
681{
682 tcg_out32(s, insn | ext << 31 | rm << 16 | rn << 5 | rd
683 | tcg_cond_to_aarch64[c] << 12);
684}
685
Richard Hendersonedd88242014-03-03 16:21:27 -0800686static void tcg_out_insn_3507(TCGContext *s, AArch64Insn insn, TCGType ext,
687 TCGReg rd, TCGReg rn)
688{
689 tcg_out32(s, insn | ext << 31 | rn << 5 | rd);
690}
691
Richard Henderson8678b712013-08-14 15:29:18 -0700692static void tcg_out_insn_3509(TCGContext *s, AArch64Insn insn, TCGType ext,
693 TCGReg rd, TCGReg rn, TCGReg rm, TCGReg ra)
694{
695 tcg_out32(s, insn | ext << 31 | rm << 16 | ra << 10 | rn << 5 | rd);
696}
697
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700698static void tcg_out_insn_3605(TCGContext *s, AArch64Insn insn, bool q,
699 TCGReg rd, TCGReg rn, int dst_idx, int src_idx)
700{
701 /* Note that bit 11 set means general register input. Therefore
702 we can handle both register sets with one function. */
703 tcg_out32(s, insn | q << 30 | (dst_idx << 16) | (src_idx << 11)
704 | (rd & 0x1f) | (~rn & 0x20) << 6 | (rn & 0x1f) << 5);
705}
706
707static void tcg_out_insn_3606(TCGContext *s, AArch64Insn insn, bool q,
708 TCGReg rd, bool op, int cmode, uint8_t imm8)
709{
710 tcg_out32(s, insn | q << 30 | op << 29 | cmode << 12 | (rd & 0x1f)
711 | (imm8 & 0xe0) << (16 - 5) | (imm8 & 0x1f) << 5);
712}
713
714static void tcg_out_insn_3614(TCGContext *s, AArch64Insn insn, bool q,
715 TCGReg rd, TCGReg rn, unsigned immhb)
716{
717 tcg_out32(s, insn | q << 30 | immhb << 16
718 | (rn & 0x1f) << 5 | (rd & 0x1f));
719}
720
721static void tcg_out_insn_3616(TCGContext *s, AArch64Insn insn, bool q,
722 unsigned size, TCGReg rd, TCGReg rn, TCGReg rm)
723{
724 tcg_out32(s, insn | q << 30 | (size << 22) | (rm & 0x1f) << 16
725 | (rn & 0x1f) << 5 | (rd & 0x1f));
726}
727
728static void tcg_out_insn_3617(TCGContext *s, AArch64Insn insn, bool q,
729 unsigned size, TCGReg rd, TCGReg rn)
730{
731 tcg_out32(s, insn | q << 30 | (size << 22)
732 | (rn & 0x1f) << 5 | (rd & 0x1f));
733}
734
Richard Henderson3d4299f2014-03-03 17:11:49 -0800735static void tcg_out_insn_3310(TCGContext *s, AArch64Insn insn,
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +0200736 TCGReg rd, TCGReg base, TCGType ext,
737 TCGReg regoff)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100738{
Richard Henderson3d4299f2014-03-03 17:11:49 -0800739 /* Note the AArch64Insn constants above are for C3.3.12. Adjust. */
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +0200740 tcg_out32(s, insn | I3312_TO_I3310 | regoff << 16 |
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700741 0x4000 | ext << 13 | base << 5 | (rd & 0x1f));
Claudio Fontana4a136e02013-06-12 16:20:22 +0100742}
743
Richard Henderson3d4299f2014-03-03 17:11:49 -0800744static void tcg_out_insn_3312(TCGContext *s, AArch64Insn insn,
745 TCGReg rd, TCGReg rn, intptr_t offset)
Claudio Fontanab1f6dc02013-06-11 10:14:09 +0200746{
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700747 tcg_out32(s, insn | (offset & 0x1ff) << 12 | rn << 5 | (rd & 0x1f));
Richard Henderson3d4299f2014-03-03 17:11:49 -0800748}
749
750static void tcg_out_insn_3313(TCGContext *s, AArch64Insn insn,
751 TCGReg rd, TCGReg rn, uintptr_t scaled_uimm)
752{
753 /* Note the AArch64Insn constants above are for C3.3.12. Adjust. */
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700754 tcg_out32(s, insn | I3312_TO_I3313 | scaled_uimm << 10
755 | rn << 5 | (rd & 0x1f));
Claudio Fontanab1f6dc02013-06-11 10:14:09 +0200756}
757
Richard Henderson7d11fc72013-08-13 14:49:18 -0700758/* Register to register move using ORR (shifted register with no shift). */
759static void tcg_out_movr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rm)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100760{
Richard Henderson7d11fc72013-08-13 14:49:18 -0700761 tcg_out_insn(s, 3510, ORR, ext, rd, TCG_REG_XZR, rm);
762}
763
764/* Register to register move using ADDI (move to/from SP). */
765static void tcg_out_movr_sp(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn)
766{
767 tcg_out_insn(s, 3401, ADDI, ext, rd, rn, 0);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100768}
769
Richard Henderson4ec4f0b2013-09-11 13:34:38 -0700770/* This function is used for the Logical (immediate) instruction group.
771 The value of LIMM must satisfy IS_LIMM. See the comment above about
772 only supporting simplified logical immediates. */
773static void tcg_out_logicali(TCGContext *s, AArch64Insn insn, TCGType ext,
774 TCGReg rd, TCGReg rn, uint64_t limm)
775{
776 unsigned h, l, r, c;
777
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +0200778 tcg_debug_assert(is_limm(limm));
Richard Henderson4ec4f0b2013-09-11 13:34:38 -0700779
780 h = clz64(limm);
781 l = ctz64(limm);
782 if (l == 0) {
783 r = 0; /* form 0....01....1 */
784 c = ctz64(~limm) - 1;
785 if (h == 0) {
786 r = clz64(~limm); /* form 1..10..01..1 */
787 c += r;
788 }
789 } else {
790 r = 64 - l; /* form 1....10....0 or 0..01..10..0 */
791 c = r - h - 1;
792 }
793 if (ext == TCG_TYPE_I32) {
794 r &= 31;
795 c &= 31;
796 }
797
798 tcg_out_insn_3404(s, insn, ext, rd, rn, ext, r, c);
799}
800
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700801static void tcg_out_dupi_vec(TCGContext *s, TCGType type,
Richard Hendersone7632cf2019-03-18 15:32:44 +0000802 TCGReg rd, tcg_target_long v64)
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700803{
804 int op, cmode, imm8;
805
806 if (is_fimm(v64, &op, &cmode, &imm8)) {
807 tcg_out_insn(s, 3606, MOVI, type == TCG_TYPE_V128, rd, op, cmode, imm8);
808 } else if (type == TCG_TYPE_V128) {
809 new_pool_l2(s, R_AARCH64_CONDBR19, s->code_ptr, 0, v64, v64);
810 tcg_out_insn(s, 3305, LDR_v128, 0, rd);
811 } else {
812 new_pool_label(s, v64, R_AARCH64_CONDBR19, s->code_ptr, 0);
813 tcg_out_insn(s, 3305, LDR_v64, 0, rd);
814 }
815}
816
Richard Hendersone7632cf2019-03-18 15:32:44 +0000817static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece,
818 TCGReg rd, TCGReg rs)
819{
820 int is_q = type - TCG_TYPE_V64;
821 tcg_out_insn(s, 3605, DUP, is_q, rd, rs, 1 << vece, 0);
822 return true;
823}
824
Richard Hendersond6ecb4a2019-03-18 12:00:39 -0700825static bool tcg_out_dupm_vec(TCGContext *s, TCGType type, unsigned vece,
826 TCGReg r, TCGReg base, intptr_t offset)
827{
828 return false;
829}
830
Richard Henderson582ab772013-08-14 15:57:36 -0700831static void tcg_out_movi(TCGContext *s, TCGType type, TCGReg rd,
832 tcg_target_long value)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100833{
Richard Hendersondfeb5fe2013-08-14 19:32:56 -0700834 tcg_target_long svalue = value;
835 tcg_target_long ivalue = ~value;
Richard Henderson55129952017-07-26 00:29:49 -0700836 tcg_target_long t0, t1, t2;
837 int s0, s1;
838 AArch64Insn opc;
Richard Henderson582ab772013-08-14 15:57:36 -0700839
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700840 switch (type) {
841 case TCG_TYPE_I32:
842 case TCG_TYPE_I64:
843 tcg_debug_assert(rd < 32);
844 break;
845
846 case TCG_TYPE_V64:
847 case TCG_TYPE_V128:
848 tcg_debug_assert(rd >= 32);
849 tcg_out_dupi_vec(s, type, rd, value);
850 return;
851
852 default:
853 g_assert_not_reached();
854 }
855
Richard Hendersondfeb5fe2013-08-14 19:32:56 -0700856 /* For 32-bit values, discard potential garbage in value. For 64-bit
857 values within [2**31, 2**32-1], we can create smaller sequences by
858 interpreting this as a negative 32-bit number, while ensuring that
859 the high 32 bits are cleared by setting SF=0. */
860 if (type == TCG_TYPE_I32 || (value & ~0xffffffffull) == 0) {
861 svalue = (int32_t)value;
Richard Henderson582ab772013-08-14 15:57:36 -0700862 value = (uint32_t)value;
Richard Hendersondfeb5fe2013-08-14 19:32:56 -0700863 ivalue = (uint32_t)ivalue;
864 type = TCG_TYPE_I32;
Richard Henderson582ab772013-08-14 15:57:36 -0700865 }
866
Richard Hendersond8918df2013-09-11 13:44:17 -0700867 /* Speed things up by handling the common case of small positive
868 and negative values specially. */
869 if ((value & ~0xffffull) == 0) {
870 tcg_out_insn(s, 3405, MOVZ, type, rd, value, 0);
871 return;
872 } else if ((ivalue & ~0xffffull) == 0) {
873 tcg_out_insn(s, 3405, MOVN, type, rd, ivalue, 0);
874 return;
875 }
876
Richard Henderson4ec4f0b2013-09-11 13:34:38 -0700877 /* Check for bitfield immediates. For the benefit of 32-bit quantities,
878 use the sign-extended value. That lets us match rotated values such
879 as 0xff0000ff with the same 64-bit logic matching 0xffffffffff0000ff. */
880 if (is_limm(svalue)) {
881 tcg_out_logicali(s, I3404_ORRI, type, rd, TCG_REG_XZR, svalue);
882 return;
883 }
884
Richard Hendersonc6e310d2013-08-10 15:28:48 -0400885 /* Look for host pointer values within 4G of the PC. This happens
886 often when loading pointers to QEMU's own data structures. */
887 if (type == TCG_TYPE_I64) {
Richard Hendersoncc74d332017-06-05 12:12:59 -0700888 tcg_target_long disp = value - (intptr_t)s->code_ptr;
889 if (disp == sextract64(disp, 0, 21)) {
890 tcg_out_insn(s, 3406, ADR, rd, disp);
891 return;
892 }
893 disp = (value >> 12) - ((intptr_t)s->code_ptr >> 12);
Richard Hendersonc6e310d2013-08-10 15:28:48 -0400894 if (disp == sextract64(disp, 0, 21)) {
895 tcg_out_insn(s, 3406, ADRP, rd, disp);
896 if (value & 0xfff) {
897 tcg_out_insn(s, 3401, ADDI, type, rd, rd, value & 0xfff);
898 }
899 return;
900 }
901 }
902
Richard Henderson55129952017-07-26 00:29:49 -0700903 /* Would it take fewer insns to begin with MOVN? */
904 if (ctpop64(value) >= 32) {
905 t0 = ivalue;
906 opc = I3405_MOVN;
907 } else {
908 t0 = value;
909 opc = I3405_MOVZ;
910 }
911 s0 = ctz64(t0) & (63 & -16);
912 t1 = t0 & ~(0xffffUL << s0);
913 s1 = ctz64(t1) & (63 & -16);
914 t2 = t1 & ~(0xffffUL << s1);
915 if (t2 == 0) {
916 tcg_out_insn_3405(s, opc, type, rd, t0 >> s0, s0);
917 if (t1 != 0) {
918 tcg_out_insn(s, 3405, MOVK, type, rd, value >> s1, s1);
919 }
920 return;
Richard Hendersondfeb5fe2013-08-14 19:32:56 -0700921 }
922
Richard Henderson55129952017-07-26 00:29:49 -0700923 /* For more than 2 insns, dump it into the constant pool. */
924 new_pool_label(s, value, R_AARCH64_CONDBR19, s->code_ptr, 0);
925 tcg_out_insn(s, 3305, LDR, 0, rd);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100926}
927
Richard Henderson3d4299f2014-03-03 17:11:49 -0800928/* Define something more legible for general use. */
929#define tcg_out_ldst_r tcg_out_insn_3310
Claudio Fontana4a136e02013-06-12 16:20:22 +0100930
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700931static void tcg_out_ldst(TCGContext *s, AArch64Insn insn, TCGReg rd,
932 TCGReg rn, intptr_t offset, int lgsize)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100933{
Richard Henderson3d4299f2014-03-03 17:11:49 -0800934 /* If the offset is naturally aligned and in range, then we can
935 use the scaled uimm12 encoding */
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700936 if (offset >= 0 && !(offset & ((1 << lgsize) - 1))) {
937 uintptr_t scaled_uimm = offset >> lgsize;
Richard Henderson3d4299f2014-03-03 17:11:49 -0800938 if (scaled_uimm <= 0xfff) {
939 tcg_out_insn_3313(s, insn, rd, rn, scaled_uimm);
940 return;
Claudio Fontanab1f6dc02013-06-11 10:14:09 +0200941 }
942 }
943
Richard Hendersona056c9f2014-03-03 23:03:51 -0500944 /* Small signed offsets can use the unscaled encoding. */
945 if (offset >= -256 && offset < 256) {
946 tcg_out_insn_3312(s, insn, rd, rn, offset);
947 return;
948 }
949
Richard Henderson3d4299f2014-03-03 17:11:49 -0800950 /* Worst-case scenario, move offset to temp register, use reg offset. */
Claudio Fontanab1f6dc02013-06-11 10:14:09 +0200951 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset);
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +0200952 tcg_out_ldst_r(s, insn, rd, rn, TCG_TYPE_I64, TCG_REG_TMP);
Claudio Fontana4a136e02013-06-12 16:20:22 +0100953}
954
Richard Henderson78113e82019-03-16 17:48:18 +0000955static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100956{
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700957 if (ret == arg) {
Richard Henderson78113e82019-03-16 17:48:18 +0000958 return true;
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700959 }
960 switch (type) {
961 case TCG_TYPE_I32:
962 case TCG_TYPE_I64:
963 if (ret < 32 && arg < 32) {
964 tcg_out_movr(s, type, ret, arg);
965 break;
966 } else if (ret < 32) {
967 tcg_out_insn(s, 3605, UMOV, type, ret, arg, 0, 0);
968 break;
969 } else if (arg < 32) {
970 tcg_out_insn(s, 3605, INS, 0, ret, arg, 4 << type, 0);
971 break;
972 }
973 /* FALLTHRU */
974
975 case TCG_TYPE_V64:
976 tcg_debug_assert(ret >= 32 && arg >= 32);
977 tcg_out_insn(s, 3616, ORR, 0, 0, ret, arg, arg);
978 break;
979 case TCG_TYPE_V128:
980 tcg_debug_assert(ret >= 32 && arg >= 32);
981 tcg_out_insn(s, 3616, ORR, 1, 0, ret, arg, arg);
982 break;
983
984 default:
985 g_assert_not_reached();
Claudio Fontana4a136e02013-06-12 16:20:22 +0100986 }
Richard Henderson78113e82019-03-16 17:48:18 +0000987 return true;
Claudio Fontana4a136e02013-06-12 16:20:22 +0100988}
989
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700990static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,
991 TCGReg base, intptr_t ofs)
Claudio Fontana4a136e02013-06-12 16:20:22 +0100992{
Richard Henderson14e4c1e2017-09-11 22:09:28 -0700993 AArch64Insn insn;
994 int lgsz;
995
996 switch (type) {
997 case TCG_TYPE_I32:
998 insn = (ret < 32 ? I3312_LDRW : I3312_LDRVS);
999 lgsz = 2;
1000 break;
1001 case TCG_TYPE_I64:
1002 insn = (ret < 32 ? I3312_LDRX : I3312_LDRVD);
1003 lgsz = 3;
1004 break;
1005 case TCG_TYPE_V64:
1006 insn = I3312_LDRVD;
1007 lgsz = 3;
1008 break;
1009 case TCG_TYPE_V128:
1010 insn = I3312_LDRVQ;
1011 lgsz = 4;
1012 break;
1013 default:
1014 g_assert_not_reached();
1015 }
1016 tcg_out_ldst(s, insn, ret, base, ofs, lgsz);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001017}
1018
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001019static void tcg_out_st(TCGContext *s, TCGType type, TCGReg src,
1020 TCGReg base, intptr_t ofs)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001021{
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001022 AArch64Insn insn;
1023 int lgsz;
1024
1025 switch (type) {
1026 case TCG_TYPE_I32:
1027 insn = (src < 32 ? I3312_STRW : I3312_STRVS);
1028 lgsz = 2;
1029 break;
1030 case TCG_TYPE_I64:
1031 insn = (src < 32 ? I3312_STRX : I3312_STRVD);
1032 lgsz = 3;
1033 break;
1034 case TCG_TYPE_V64:
1035 insn = I3312_STRVD;
1036 lgsz = 3;
1037 break;
1038 case TCG_TYPE_V128:
1039 insn = I3312_STRVQ;
1040 lgsz = 4;
1041 break;
1042 default:
1043 g_assert_not_reached();
1044 }
1045 tcg_out_ldst(s, insn, src, base, ofs, lgsz);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001046}
1047
Richard Henderson59d7c142016-06-19 22:59:13 -07001048static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
1049 TCGReg base, intptr_t ofs)
1050{
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001051 if (type <= TCG_TYPE_I64 && val == 0) {
Richard Henderson59d7c142016-06-19 22:59:13 -07001052 tcg_out_st(s, type, TCG_REG_XZR, base, ofs);
1053 return true;
1054 }
1055 return false;
1056}
1057
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001058static inline void tcg_out_bfm(TCGContext *s, TCGType ext, TCGReg rd,
1059 TCGReg rn, unsigned int a, unsigned int b)
1060{
1061 tcg_out_insn(s, 3402, BFM, ext, rd, rn, ext, a, b);
1062}
1063
Richard Henderson7763ffa2013-08-15 11:11:00 -07001064static inline void tcg_out_ubfm(TCGContext *s, TCGType ext, TCGReg rd,
1065 TCGReg rn, unsigned int a, unsigned int b)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001066{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001067 tcg_out_insn(s, 3402, UBFM, ext, rd, rn, ext, a, b);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001068}
1069
Richard Henderson7763ffa2013-08-15 11:11:00 -07001070static inline void tcg_out_sbfm(TCGContext *s, TCGType ext, TCGReg rd,
1071 TCGReg rn, unsigned int a, unsigned int b)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001072{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001073 tcg_out_insn(s, 3402, SBFM, ext, rd, rn, ext, a, b);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001074}
1075
Richard Henderson7763ffa2013-08-15 11:11:00 -07001076static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001077 TCGReg rn, TCGReg rm, unsigned int a)
1078{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001079 tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001080}
1081
Richard Henderson7763ffa2013-08-15 11:11:00 -07001082static inline void tcg_out_shl(TCGContext *s, TCGType ext,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001083 TCGReg rd, TCGReg rn, unsigned int m)
1084{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001085 int bits = ext ? 64 : 32;
1086 int max = bits - 1;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001087 tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max));
1088}
1089
Richard Henderson7763ffa2013-08-15 11:11:00 -07001090static inline void tcg_out_shr(TCGContext *s, TCGType ext,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001091 TCGReg rd, TCGReg rn, unsigned int m)
1092{
1093 int max = ext ? 63 : 31;
1094 tcg_out_ubfm(s, ext, rd, rn, m & max, max);
1095}
1096
Richard Henderson7763ffa2013-08-15 11:11:00 -07001097static inline void tcg_out_sar(TCGContext *s, TCGType ext,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001098 TCGReg rd, TCGReg rn, unsigned int m)
1099{
1100 int max = ext ? 63 : 31;
1101 tcg_out_sbfm(s, ext, rd, rn, m & max, max);
1102}
1103
Richard Henderson7763ffa2013-08-15 11:11:00 -07001104static inline void tcg_out_rotr(TCGContext *s, TCGType ext,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001105 TCGReg rd, TCGReg rn, unsigned int m)
1106{
1107 int max = ext ? 63 : 31;
1108 tcg_out_extr(s, ext, rd, rn, rn, m & max);
1109}
1110
Richard Henderson7763ffa2013-08-15 11:11:00 -07001111static inline void tcg_out_rotl(TCGContext *s, TCGType ext,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001112 TCGReg rd, TCGReg rn, unsigned int m)
1113{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001114 int bits = ext ? 64 : 32;
1115 int max = bits - 1;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001116 tcg_out_extr(s, ext, rd, rn, rn, bits - (m & max));
1117}
1118
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001119static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd,
1120 TCGReg rn, unsigned lsb, unsigned width)
1121{
1122 unsigned size = ext ? 64 : 32;
1123 unsigned a = (size - lsb) & (size - 1);
1124 unsigned b = width - 1;
1125 tcg_out_bfm(s, ext, rd, rn, a, b);
1126}
1127
Richard Henderson90f1cd92013-08-14 09:56:14 -07001128static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg a,
1129 tcg_target_long b, bool const_b)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001130{
Richard Henderson90f1cd92013-08-14 09:56:14 -07001131 if (const_b) {
1132 /* Using CMP or CMN aliases. */
1133 if (b >= 0) {
1134 tcg_out_insn(s, 3401, SUBSI, ext, TCG_REG_XZR, a, b);
1135 } else {
1136 tcg_out_insn(s, 3401, ADDSI, ext, TCG_REG_XZR, a, -b);
1137 }
1138 } else {
1139 /* Using CMP alias SUBS wzr, Wn, Wm */
1140 tcg_out_insn(s, 3502, SUBS, ext, TCG_REG_XZR, a, b);
1141 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001142}
1143
Richard Henderson8587c302014-04-28 12:02:31 -07001144static inline void tcg_out_goto(TCGContext *s, tcg_insn_unit *target)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001145{
Richard Henderson8587c302014-04-28 12:02:31 -07001146 ptrdiff_t offset = target - s->code_ptr;
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +02001147 tcg_debug_assert(offset == sextract64(offset, 0, 26));
Richard Henderson81d8a5e2013-08-14 20:05:51 -07001148 tcg_out_insn(s, 3206, B, offset);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001149}
1150
Pranith Kumar23b7aa12017-06-30 10:36:12 -04001151static inline void tcg_out_goto_long(TCGContext *s, tcg_insn_unit *target)
1152{
1153 ptrdiff_t offset = target - s->code_ptr;
1154 if (offset == sextract64(offset, 0, 26)) {
1155 tcg_out_insn(s, 3206, BL, offset);
1156 } else {
1157 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target);
1158 tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
1159 }
1160}
1161
Claudio Fontana4a136e02013-06-12 16:20:22 +01001162static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
1163{
Richard Henderson81d8a5e2013-08-14 20:05:51 -07001164 tcg_out_insn(s, 3207, BLR, reg);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001165}
1166
Richard Henderson8587c302014-04-28 12:02:31 -07001167static inline void tcg_out_call(TCGContext *s, tcg_insn_unit *target)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001168{
Richard Henderson8587c302014-04-28 12:02:31 -07001169 ptrdiff_t offset = target - s->code_ptr;
1170 if (offset == sextract64(offset, 0, 26)) {
Richard Henderson81d8a5e2013-08-14 20:05:51 -07001171 tcg_out_insn(s, 3206, BL, offset);
Richard Henderson8587c302014-04-28 12:02:31 -07001172 } else {
1173 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target);
1174 tcg_out_callr(s, TCG_REG_TMP);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001175 }
1176}
1177
Richard Hendersona8583392017-07-31 22:02:31 -07001178void tb_target_set_jmp_target(uintptr_t tc_ptr, uintptr_t jmp_addr,
1179 uintptr_t addr)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001180{
Pranith Kumarb68686b2017-06-30 10:36:13 -04001181 tcg_insn_unit i1, i2;
1182 TCGType rt = TCG_TYPE_I64;
1183 TCGReg rd = TCG_REG_TMP;
1184 uint64_t pair;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001185
Pranith Kumarb68686b2017-06-30 10:36:13 -04001186 ptrdiff_t offset = addr - jmp_addr;
1187
1188 if (offset == sextract64(offset, 0, 26)) {
1189 i1 = I3206_B | ((offset >> 2) & 0x3ffffff);
1190 i2 = NOP;
1191 } else {
1192 offset = (addr >> 12) - (jmp_addr >> 12);
1193
1194 /* patch ADRP */
1195 i1 = I3406_ADRP | (offset & 3) << 29 | (offset & 0x1ffffc) << (5 - 2) | rd;
1196 /* patch ADDI */
1197 i2 = I3401_ADDI | rt << 31 | (addr & 0xfff) << 10 | rd << 5 | rd;
1198 }
1199 pair = (uint64_t)i2 << 32 | i1;
1200 atomic_set((uint64_t *)jmp_addr, pair);
1201 flush_icache_range(jmp_addr, jmp_addr + 8);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001202}
1203
Richard Hendersonbec16312015-02-13 13:39:54 -08001204static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001205{
Claudio Fontana4a136e02013-06-12 16:20:22 +01001206 if (!l->has_value) {
Richard Hendersonbec16312015-02-13 13:39:54 -08001207 tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, l, 0);
Richard Henderson733589b2018-11-29 20:52:47 +00001208 tcg_out_insn(s, 3206, B, 0);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001209 } else {
Richard Henderson8587c302014-04-28 12:02:31 -07001210 tcg_out_goto(s, l->u.value_ptr);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001211 }
1212}
1213
Pranith Kumardc1eccd2017-02-17 10:43:11 -05001214static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a,
Richard Hendersonbec16312015-02-13 13:39:54 -08001215 TCGArg b, bool b_const, TCGLabel *l)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001216{
Richard Hendersoncae1f6f2014-02-27 19:31:57 -05001217 intptr_t offset;
Richard Henderson3d9e69a2014-02-27 19:55:30 -05001218 bool need_cmp;
Richard Hendersoncae1f6f2014-02-27 19:31:57 -05001219
Richard Henderson3d9e69a2014-02-27 19:55:30 -05001220 if (b_const && b == 0 && (c == TCG_COND_EQ || c == TCG_COND_NE)) {
1221 need_cmp = false;
1222 } else {
1223 need_cmp = true;
1224 tcg_out_cmp(s, ext, a, b, b_const);
1225 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001226
1227 if (!l->has_value) {
Richard Hendersonbec16312015-02-13 13:39:54 -08001228 tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0);
Richard Hendersoncae1f6f2014-02-27 19:31:57 -05001229 offset = tcg_in32(s) >> 5;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001230 } else {
Richard Henderson8587c302014-04-28 12:02:31 -07001231 offset = l->u.value_ptr - s->code_ptr;
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +02001232 tcg_debug_assert(offset == sextract64(offset, 0, 19));
Claudio Fontana4a136e02013-06-12 16:20:22 +01001233 }
Richard Hendersoncae1f6f2014-02-27 19:31:57 -05001234
Richard Henderson3d9e69a2014-02-27 19:55:30 -05001235 if (need_cmp) {
1236 tcg_out_insn(s, 3202, B_C, c, offset);
1237 } else if (c == TCG_COND_EQ) {
1238 tcg_out_insn(s, 3201, CBZ, ext, a, offset);
1239 } else {
1240 tcg_out_insn(s, 3201, CBNZ, ext, a, offset);
1241 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001242}
1243
Richard Hendersonedd88242014-03-03 16:21:27 -08001244static inline void tcg_out_rev64(TCGContext *s, TCGReg rd, TCGReg rn)
Claudio Fontana9c4a0592013-06-12 16:20:23 +01001245{
Richard Hendersonedd88242014-03-03 16:21:27 -08001246 tcg_out_insn(s, 3507, REV64, TCG_TYPE_I64, rd, rn);
Claudio Fontana9c4a0592013-06-12 16:20:23 +01001247}
1248
Richard Hendersonedd88242014-03-03 16:21:27 -08001249static inline void tcg_out_rev32(TCGContext *s, TCGReg rd, TCGReg rn)
Claudio Fontana9c4a0592013-06-12 16:20:23 +01001250{
Richard Hendersonedd88242014-03-03 16:21:27 -08001251 tcg_out_insn(s, 3507, REV32, TCG_TYPE_I32, rd, rn);
1252}
1253
1254static inline void tcg_out_rev16(TCGContext *s, TCGReg rd, TCGReg rn)
1255{
1256 tcg_out_insn(s, 3507, REV16, TCG_TYPE_I32, rd, rn);
Claudio Fontana9c4a0592013-06-12 16:20:23 +01001257}
1258
Richard Henderson929f8b52014-03-03 16:12:21 -08001259static inline void tcg_out_sxt(TCGContext *s, TCGType ext, TCGMemOp s_bits,
Claudio Fontana31f12752013-06-12 16:20:23 +01001260 TCGReg rd, TCGReg rn)
1261{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001262 /* Using ALIASes SXTB, SXTH, SXTW, of SBFM Xd, Xn, #0, #7|15|31 */
Richard Henderson929f8b52014-03-03 16:12:21 -08001263 int bits = (8 << s_bits) - 1;
Claudio Fontana31f12752013-06-12 16:20:23 +01001264 tcg_out_sbfm(s, ext, rd, rn, 0, bits);
1265}
1266
Richard Henderson929f8b52014-03-03 16:12:21 -08001267static inline void tcg_out_uxt(TCGContext *s, TCGMemOp s_bits,
Claudio Fontana31f12752013-06-12 16:20:23 +01001268 TCGReg rd, TCGReg rn)
1269{
Richard Hendersonb3c56df2013-08-14 13:05:07 -07001270 /* Using ALIASes UXTB, UXTH of UBFM Wd, Wn, #0, #7|15 */
Richard Henderson929f8b52014-03-03 16:12:21 -08001271 int bits = (8 << s_bits) - 1;
Claudio Fontana31f12752013-06-12 16:20:23 +01001272 tcg_out_ubfm(s, 0, rd, rn, 0, bits);
1273}
1274
Richard Henderson90f1cd92013-08-14 09:56:14 -07001275static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd,
1276 TCGReg rn, int64_t aimm)
1277{
1278 if (aimm >= 0) {
1279 tcg_out_insn(s, 3401, ADDI, ext, rd, rn, aimm);
1280 } else {
1281 tcg_out_insn(s, 3401, SUBI, ext, rd, rn, -aimm);
1282 }
1283}
1284
Pranith Kumardc1eccd2017-02-17 10:43:11 -05001285static inline void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl,
Richard Hendersonc6e929e2013-08-14 13:30:07 -07001286 TCGReg rh, TCGReg al, TCGReg ah,
1287 tcg_target_long bl, tcg_target_long bh,
1288 bool const_bl, bool const_bh, bool sub)
1289{
1290 TCGReg orig_rl = rl;
1291 AArch64Insn insn;
1292
1293 if (rl == ah || (!const_bh && rl == bh)) {
1294 rl = TCG_REG_TMP;
1295 }
1296
1297 if (const_bl) {
1298 insn = I3401_ADDSI;
1299 if ((bl < 0) ^ sub) {
1300 insn = I3401_SUBSI;
1301 bl = -bl;
1302 }
Richard Hendersonb1eb20d2016-12-07 10:07:26 -08001303 if (unlikely(al == TCG_REG_XZR)) {
1304 /* ??? We want to allow al to be zero for the benefit of
1305 negation via subtraction. However, that leaves open the
1306 possibility of adding 0+const in the low part, and the
1307 immediate add instructions encode XSP not XZR. Don't try
1308 anything more elaborate here than loading another zero. */
1309 al = TCG_REG_TMP;
1310 tcg_out_movi(s, ext, al, 0);
1311 }
Richard Hendersonc6e929e2013-08-14 13:30:07 -07001312 tcg_out_insn_3401(s, insn, ext, rl, al, bl);
1313 } else {
1314 tcg_out_insn_3502(s, sub ? I3502_SUBS : I3502_ADDS, ext, rl, al, bl);
1315 }
1316
1317 insn = I3503_ADC;
1318 if (const_bh) {
1319 /* Note that the only two constants we support are 0 and -1, and
1320 that SBC = rn + ~rm + c, so adc -1 is sbc 0, and vice-versa. */
1321 if ((bh != 0) ^ sub) {
1322 insn = I3503_SBC;
1323 }
1324 bh = TCG_REG_XZR;
1325 } else if (sub) {
1326 insn = I3503_SBC;
1327 }
1328 tcg_out_insn_3503(s, insn, ext, rh, ah, bh);
1329
Richard Hendersonb8250252014-04-03 14:41:34 -04001330 tcg_out_mov(s, ext, orig_rl, rl);
Richard Hendersonc6e929e2013-08-14 13:30:07 -07001331}
1332
Pranith Kumarc7a59c22016-07-14 16:20:15 -04001333static inline void tcg_out_mb(TCGContext *s, TCGArg a0)
1334{
1335 static const uint32_t sync[] = {
1336 [0 ... TCG_MO_ALL] = DMB_ISH | DMB_LD | DMB_ST,
1337 [TCG_MO_ST_ST] = DMB_ISH | DMB_ST,
1338 [TCG_MO_LD_LD] = DMB_ISH | DMB_LD,
1339 [TCG_MO_LD_ST] = DMB_ISH | DMB_LD,
1340 [TCG_MO_LD_ST | TCG_MO_LD_LD] = DMB_ISH | DMB_LD,
1341 };
1342 tcg_out32(s, sync[a0 & TCG_MO_ALL]);
1343}
1344
Richard Henderson53c76c12016-11-16 14:03:28 +01001345static void tcg_out_cltz(TCGContext *s, TCGType ext, TCGReg d,
1346 TCGReg a0, TCGArg b, bool const_b, bool is_ctz)
1347{
1348 TCGReg a1 = a0;
1349 if (is_ctz) {
1350 a1 = TCG_REG_TMP;
1351 tcg_out_insn(s, 3507, RBIT, ext, a1, a0);
1352 }
1353 if (const_b && b == (ext ? 64 : 32)) {
1354 tcg_out_insn(s, 3507, CLZ, ext, d, a1);
1355 } else {
1356 AArch64Insn sel = I3506_CSEL;
1357
1358 tcg_out_cmp(s, ext, a0, 0, 1);
1359 tcg_out_insn(s, 3507, CLZ, ext, TCG_REG_TMP, a1);
1360
1361 if (const_b) {
1362 if (b == -1) {
1363 b = TCG_REG_XZR;
1364 sel = I3506_CSINV;
1365 } else if (b == 0) {
1366 b = TCG_REG_XZR;
1367 } else {
1368 tcg_out_movi(s, ext, d, b);
1369 b = d;
1370 }
1371 }
1372 tcg_out_insn_3506(s, sel, ext, d, TCG_REG_TMP, b, TCG_COND_NE);
1373 }
1374}
1375
Claudio Fontana4a136e02013-06-12 16:20:22 +01001376#ifdef CONFIG_SOFTMMU
Richard Henderson659ef5c2017-07-30 12:30:41 -07001377#include "tcg-ldst.inc.c"
1378
Richard Henderson023261e2013-10-01 13:47:38 -07001379/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
Richard Henderson3972ef62015-05-13 09:10:33 -07001380 * TCGMemOpIdx oi, uintptr_t ra)
Richard Henderson023261e2013-10-01 13:47:38 -07001381 */
Richard Henderson8587c302014-04-28 12:02:31 -07001382static void * const qemu_ld_helpers[16] = {
Richard Hendersonde61d142014-02-27 14:42:18 -05001383 [MO_UB] = helper_ret_ldub_mmu,
1384 [MO_LEUW] = helper_le_lduw_mmu,
1385 [MO_LEUL] = helper_le_ldul_mmu,
1386 [MO_LEQ] = helper_le_ldq_mmu,
1387 [MO_BEUW] = helper_be_lduw_mmu,
1388 [MO_BEUL] = helper_be_ldul_mmu,
1389 [MO_BEQ] = helper_be_ldq_mmu,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001390};
1391
Richard Henderson023261e2013-10-01 13:47:38 -07001392/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
Richard Henderson3972ef62015-05-13 09:10:33 -07001393 * uintxx_t val, TCGMemOpIdx oi,
1394 * uintptr_t ra)
Richard Henderson023261e2013-10-01 13:47:38 -07001395 */
Richard Henderson8587c302014-04-28 12:02:31 -07001396static void * const qemu_st_helpers[16] = {
Richard Hendersonde61d142014-02-27 14:42:18 -05001397 [MO_UB] = helper_ret_stb_mmu,
1398 [MO_LEUW] = helper_le_stw_mmu,
1399 [MO_LEUL] = helper_le_stl_mmu,
1400 [MO_LEQ] = helper_le_stq_mmu,
1401 [MO_BEUW] = helper_be_stw_mmu,
1402 [MO_BEUL] = helper_be_stl_mmu,
1403 [MO_BEQ] = helper_be_stq_mmu,
Claudio Fontana4a136e02013-06-12 16:20:22 +01001404};
1405
Richard Henderson8587c302014-04-28 12:02:31 -07001406static inline void tcg_out_adr(TCGContext *s, TCGReg rd, void *target)
Richard Hendersondc0c8aa2013-08-12 06:32:52 -10001407{
Richard Henderson8587c302014-04-28 12:02:31 -07001408 ptrdiff_t offset = tcg_pcrel_diff(s, target);
Aurelien Jarnoeabb7b92016-04-21 10:48:49 +02001409 tcg_debug_assert(offset == sextract64(offset, 0, 21));
Richard Henderson8587c302014-04-28 12:02:31 -07001410 tcg_out_insn(s, 3406, ADR, rd, offset);
Richard Hendersondc0c8aa2013-08-12 06:32:52 -10001411}
1412
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001413static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001414{
Richard Henderson3972ef62015-05-13 09:10:33 -07001415 TCGMemOpIdx oi = lb->oi;
1416 TCGMemOp opc = get_memop(oi);
Richard Henderson929f8b52014-03-03 16:12:21 -08001417 TCGMemOp size = opc & MO_SIZE;
1418
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001419 if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
1420 return false;
1421 }
Richard Henderson017a86f2014-03-03 17:55:33 -08001422
Richard Henderson3972ef62015-05-13 09:10:33 -07001423 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
Richard Hendersonb8250252014-04-03 14:41:34 -04001424 tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg);
Richard Henderson3972ef62015-05-13 09:10:33 -07001425 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, oi);
Richard Henderson8587c302014-04-28 12:02:31 -07001426 tcg_out_adr(s, TCG_REG_X3, lb->raddr);
Richard Henderson2b7ec662015-05-29 09:16:51 -07001427 tcg_out_call(s, qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)]);
Richard Henderson929f8b52014-03-03 16:12:21 -08001428 if (opc & MO_SIGN) {
Richard Henderson9c538892014-09-02 13:59:47 -07001429 tcg_out_sxt(s, lb->type, size, lb->datalo_reg, TCG_REG_X0);
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001430 } else {
Richard Hendersonb8250252014-04-03 14:41:34 -04001431 tcg_out_mov(s, size == MO_64, lb->datalo_reg, TCG_REG_X0);
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001432 }
1433
Richard Henderson8587c302014-04-28 12:02:31 -07001434 tcg_out_goto(s, lb->raddr);
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001435 return true;
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001436}
1437
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001438static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001439{
Richard Henderson3972ef62015-05-13 09:10:33 -07001440 TCGMemOpIdx oi = lb->oi;
1441 TCGMemOp opc = get_memop(oi);
Richard Hendersonde61d142014-02-27 14:42:18 -05001442 TCGMemOp size = opc & MO_SIZE;
Richard Henderson929f8b52014-03-03 16:12:21 -08001443
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001444 if (!reloc_pc19(lb->label_ptr[0], s->code_ptr)) {
1445 return false;
1446 }
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001447
Richard Henderson3972ef62015-05-13 09:10:33 -07001448 tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
Richard Hendersonb8250252014-04-03 14:41:34 -04001449 tcg_out_mov(s, TARGET_LONG_BITS == 64, TCG_REG_X1, lb->addrlo_reg);
1450 tcg_out_mov(s, size == MO_64, TCG_REG_X2, lb->datalo_reg);
Richard Henderson3972ef62015-05-13 09:10:33 -07001451 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, oi);
Richard Henderson8587c302014-04-28 12:02:31 -07001452 tcg_out_adr(s, TCG_REG_X4, lb->raddr);
Richard Henderson2b7ec662015-05-29 09:16:51 -07001453 tcg_out_call(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
Richard Henderson8587c302014-04-28 12:02:31 -07001454 tcg_out_goto(s, lb->raddr);
Richard Hendersonaeee05f2019-04-21 14:51:00 -07001455 return true;
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001456}
1457
Richard Henderson3972ef62015-05-13 09:10:33 -07001458static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
Richard Henderson9c538892014-09-02 13:59:47 -07001459 TCGType ext, TCGReg data_reg, TCGReg addr_reg,
Richard Henderson3972ef62015-05-13 09:10:33 -07001460 tcg_insn_unit *raddr, tcg_insn_unit *label_ptr)
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001461{
Richard Henderson9ecefc82013-10-03 14:51:24 -05001462 TCGLabelQemuLdst *label = new_ldst_label(s);
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001463
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001464 label->is_ld = is_ld;
Richard Henderson3972ef62015-05-13 09:10:33 -07001465 label->oi = oi;
Richard Henderson9c538892014-09-02 13:59:47 -07001466 label->type = ext;
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001467 label->datalo_reg = data_reg;
1468 label->addrlo_reg = addr_reg;
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001469 label->raddr = raddr;
1470 label->label_ptr[0] = label_ptr;
1471}
1472
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001473/* We expect tlb_mask to be before tlb_table. */
1474QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table) <
1475 offsetof(CPUArchState, tlb_mask));
1476
1477/* We expect to use a 24-bit unsigned offset from ENV. */
1478QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1])
1479 > 0xffffff);
1480
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001481/* Load and compare a TLB entry, emitting the conditional jump to the
1482 slow path for the failure case, which will be patched later when finalizing
1483 the slow path. Generated code returns the host addend in X1,
1484 clobbers X0,X2,X3,TMP. */
Richard Henderson9ee14902015-08-17 12:18:05 -07001485static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg, TCGMemOp opc,
Richard Henderson8587c302014-04-28 12:02:31 -07001486 tcg_insn_unit **label_ptr, int mem_index,
1487 bool is_read)
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001488{
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001489 int mask_ofs = offsetof(CPUArchState, tlb_mask[mem_index]);
1490 int table_ofs = offsetof(CPUArchState, tlb_table[mem_index]);
Richard Henderson85aa8082016-07-14 12:43:06 -07001491 unsigned a_bits = get_alignment_bits(opc);
1492 unsigned s_bits = opc & MO_SIZE;
1493 unsigned a_mask = (1u << a_bits) - 1;
1494 unsigned s_mask = (1u << s_bits) - 1;
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001495 TCGReg mask_base = TCG_AREG0, table_base = TCG_AREG0, x3;
1496 TCGType mask_type;
1497 uint64_t compare_mask;
1498
1499 if (table_ofs > 0xfff) {
1500 int table_hi = table_ofs & ~0xfff;
1501 int mask_hi = mask_ofs & ~0xfff;
1502
1503 table_base = TCG_REG_X1;
1504 if (mask_hi == table_hi) {
1505 mask_base = table_base;
1506 } else if (mask_hi) {
1507 mask_base = TCG_REG_X0;
1508 tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64,
1509 mask_base, TCG_AREG0, mask_hi);
1510 }
1511 tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64,
1512 table_base, TCG_AREG0, table_hi);
1513 mask_ofs -= mask_hi;
1514 table_ofs -= table_hi;
1515 }
1516
1517 mask_type = (TARGET_PAGE_BITS + CPU_TLB_DYN_MAX_BITS > 32
1518 ? TCG_TYPE_I64 : TCG_TYPE_I32);
1519
1520 /* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */
1521 tcg_out_ld(s, mask_type, TCG_REG_X0, mask_base, mask_ofs);
1522 tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_X1, table_base, table_ofs);
1523
1524 /* Extract the TLB index from the address into X0. */
1525 tcg_out_insn(s, 3502S, AND_LSR, mask_type == TCG_TYPE_I64,
1526 TCG_REG_X0, TCG_REG_X0, addr_reg,
1527 TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
1528
1529 /* Add the tlb_table pointer, creating the CPUTLBEntry address into X1. */
1530 tcg_out_insn(s, 3502, ADD, 1, TCG_REG_X1, TCG_REG_X1, TCG_REG_X0);
1531
1532 /* Load the tlb comparator into X0, and the fast path addend into X1. */
1533 tcg_out_ld(s, TCG_TYPE_TL, TCG_REG_X0, TCG_REG_X1, is_read
1534 ? offsetof(CPUTLBEntry, addr_read)
1535 : offsetof(CPUTLBEntry, addr_write));
1536 tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_X1, TCG_REG_X1,
1537 offsetof(CPUTLBEntry, addend));
Richard Henderson9ee14902015-08-17 12:18:05 -07001538
1539 /* For aligned accesses, we check the first byte and include the alignment
1540 bits within the address. For unaligned access, we check that we don't
1541 cross pages using the address of the last byte of the access. */
Richard Henderson85aa8082016-07-14 12:43:06 -07001542 if (a_bits >= s_bits) {
Richard Henderson9ee14902015-08-17 12:18:05 -07001543 x3 = addr_reg;
1544 } else {
1545 tcg_out_insn(s, 3401, ADDI, TARGET_LONG_BITS == 64,
Richard Henderson85aa8082016-07-14 12:43:06 -07001546 TCG_REG_X3, addr_reg, s_mask - a_mask);
Richard Henderson9ee14902015-08-17 12:18:05 -07001547 x3 = TCG_REG_X3;
1548 }
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001549 compare_mask = (uint64_t)TARGET_PAGE_MASK | a_mask;
Richard Henderson6f472462013-08-10 14:56:12 -04001550
Richard Henderson9ee14902015-08-17 12:18:05 -07001551 /* Store the page mask part of the address into X3. */
1552 tcg_out_logicali(s, I3404_ANDI, TARGET_LONG_BITS == 64,
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001553 TCG_REG_X3, x3, compare_mask);
Richard Henderson6f472462013-08-10 14:56:12 -04001554
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001555 /* Perform the address comparison. */
Richard Hendersonf7bcd962018-12-25 22:33:50 +00001556 tcg_out_cmp(s, TARGET_LONG_BITS == 64, TCG_REG_X0, TCG_REG_X3, 0);
Richard Henderson6f472462013-08-10 14:56:12 -04001557
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001558 /* If not equal, we jump to the slow path. */
Richard Henderson6f472462013-08-10 14:56:12 -04001559 *label_ptr = s->code_ptr;
Richard Henderson733589b2018-11-29 20:52:47 +00001560 tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
Jani Kokkonenc6d8ed22013-07-10 17:02:00 +02001561}
1562
1563#endif /* CONFIG_SOFTMMU */
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001564
Richard Henderson9c538892014-09-02 13:59:47 -07001565static void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp memop, TCGType ext,
Paolo Bonziniffc63722015-07-15 17:27:01 +02001566 TCGReg data_r, TCGReg addr_r,
1567 TCGType otype, TCGReg off_r)
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001568{
Richard Henderson9e4177a2014-02-26 18:54:38 -05001569 const TCGMemOp bswap = memop & MO_BSWAP;
1570
1571 switch (memop & MO_SSIZE) {
1572 case MO_UB:
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001573 tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001574 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001575 case MO_SB:
Richard Henderson9c538892014-09-02 13:59:47 -07001576 tcg_out_ldst_r(s, ext ? I3312_LDRSBX : I3312_LDRSBW,
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001577 data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001578 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001579 case MO_UW:
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001580 tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, otype, off_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001581 if (bswap) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001582 tcg_out_rev16(s, data_r, data_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001583 }
1584 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001585 case MO_SW:
1586 if (bswap) {
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001587 tcg_out_ldst_r(s, I3312_LDRH, data_r, addr_r, otype, off_r);
Richard Hendersonedd88242014-03-03 16:21:27 -08001588 tcg_out_rev16(s, data_r, data_r);
Richard Henderson9c538892014-09-02 13:59:47 -07001589 tcg_out_sxt(s, ext, MO_16, data_r, data_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001590 } else {
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001591 tcg_out_ldst_r(s, (ext ? I3312_LDRSHX : I3312_LDRSHW),
1592 data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001593 }
1594 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001595 case MO_UL:
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001596 tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, otype, off_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001597 if (bswap) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001598 tcg_out_rev32(s, data_r, data_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001599 }
1600 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001601 case MO_SL:
1602 if (bswap) {
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001603 tcg_out_ldst_r(s, I3312_LDRW, data_r, addr_r, otype, off_r);
Richard Hendersonedd88242014-03-03 16:21:27 -08001604 tcg_out_rev32(s, data_r, data_r);
Richard Henderson929f8b52014-03-03 16:12:21 -08001605 tcg_out_sxt(s, TCG_TYPE_I64, MO_32, data_r, data_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001606 } else {
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001607 tcg_out_ldst_r(s, I3312_LDRSWX, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001608 }
1609 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001610 case MO_Q:
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001611 tcg_out_ldst_r(s, I3312_LDRX, data_r, addr_r, otype, off_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001612 if (bswap) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001613 tcg_out_rev64(s, data_r, data_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001614 }
1615 break;
1616 default:
1617 tcg_abort();
1618 }
1619}
1620
Richard Henderson9e4177a2014-02-26 18:54:38 -05001621static void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp memop,
Paolo Bonziniffc63722015-07-15 17:27:01 +02001622 TCGReg data_r, TCGReg addr_r,
1623 TCGType otype, TCGReg off_r)
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001624{
Richard Henderson9e4177a2014-02-26 18:54:38 -05001625 const TCGMemOp bswap = memop & MO_BSWAP;
1626
1627 switch (memop & MO_SIZE) {
1628 case MO_8:
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001629 tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001630 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001631 case MO_16:
Richard Hendersone81864a2014-03-03 21:58:46 -05001632 if (bswap && data_r != TCG_REG_XZR) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001633 tcg_out_rev16(s, TCG_REG_TMP, data_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001634 data_r = TCG_REG_TMP;
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001635 }
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001636 tcg_out_ldst_r(s, I3312_STRH, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001637 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001638 case MO_32:
Richard Hendersone81864a2014-03-03 21:58:46 -05001639 if (bswap && data_r != TCG_REG_XZR) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001640 tcg_out_rev32(s, TCG_REG_TMP, data_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001641 data_r = TCG_REG_TMP;
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001642 }
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001643 tcg_out_ldst_r(s, I3312_STRW, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001644 break;
Richard Henderson9e4177a2014-02-26 18:54:38 -05001645 case MO_64:
Richard Hendersone81864a2014-03-03 21:58:46 -05001646 if (bswap && data_r != TCG_REG_XZR) {
Richard Hendersonedd88242014-03-03 16:21:27 -08001647 tcg_out_rev64(s, TCG_REG_TMP, data_r);
Richard Henderson9e4177a2014-02-26 18:54:38 -05001648 data_r = TCG_REG_TMP;
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001649 }
Paolo Bonzini6c0f0c02015-07-15 17:27:00 +02001650 tcg_out_ldst_r(s, I3312_STRX, data_r, addr_r, otype, off_r);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001651 break;
1652 default:
1653 tcg_abort();
1654 }
1655}
Claudio Fontana4a136e02013-06-12 16:20:22 +01001656
Richard Henderson667b1cd2014-04-03 13:54:28 -04001657static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
Richard Henderson59227d52015-05-12 11:51:44 -07001658 TCGMemOpIdx oi, TCGType ext)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001659{
Richard Henderson59227d52015-05-12 11:51:44 -07001660 TCGMemOp memop = get_memop(oi);
Richard Henderson80adb8f2015-07-23 18:04:52 -04001661 const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001662#ifdef CONFIG_SOFTMMU
Richard Henderson59227d52015-05-12 11:51:44 -07001663 unsigned mem_index = get_mmuidx(oi);
Richard Henderson8587c302014-04-28 12:02:31 -07001664 tcg_insn_unit *label_ptr;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001665
Richard Henderson9ee14902015-08-17 12:18:05 -07001666 tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 1);
Richard Henderson80adb8f2015-07-23 18:04:52 -04001667 tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
1668 TCG_REG_X1, otype, addr_reg);
Richard Henderson3972ef62015-05-13 09:10:33 -07001669 add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg,
1670 s->code_ptr, label_ptr);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001671#else /* !CONFIG_SOFTMMU */
Richard Henderson352bcb02015-09-01 15:58:02 -04001672 if (USE_GUEST_BASE) {
1673 tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
1674 TCG_REG_GUEST_BASE, otype, addr_reg);
1675 } else {
1676 tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
1677 addr_reg, TCG_TYPE_I64, TCG_REG_XZR);
1678 }
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001679#endif /* CONFIG_SOFTMMU */
Claudio Fontana4a136e02013-06-12 16:20:22 +01001680}
1681
Richard Henderson667b1cd2014-04-03 13:54:28 -04001682static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg,
Richard Henderson59227d52015-05-12 11:51:44 -07001683 TCGMemOpIdx oi)
Claudio Fontana4a136e02013-06-12 16:20:22 +01001684{
Richard Henderson59227d52015-05-12 11:51:44 -07001685 TCGMemOp memop = get_memop(oi);
Richard Henderson80adb8f2015-07-23 18:04:52 -04001686 const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001687#ifdef CONFIG_SOFTMMU
Richard Henderson59227d52015-05-12 11:51:44 -07001688 unsigned mem_index = get_mmuidx(oi);
Richard Henderson8587c302014-04-28 12:02:31 -07001689 tcg_insn_unit *label_ptr;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001690
Richard Henderson9ee14902015-08-17 12:18:05 -07001691 tcg_out_tlb_read(s, addr_reg, memop, &label_ptr, mem_index, 0);
Richard Henderson80adb8f2015-07-23 18:04:52 -04001692 tcg_out_qemu_st_direct(s, memop, data_reg,
1693 TCG_REG_X1, otype, addr_reg);
Richard Henderson9ee14902015-08-17 12:18:05 -07001694 add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64,
1695 data_reg, addr_reg, s->code_ptr, label_ptr);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001696#else /* !CONFIG_SOFTMMU */
Richard Henderson352bcb02015-09-01 15:58:02 -04001697 if (USE_GUEST_BASE) {
1698 tcg_out_qemu_st_direct(s, memop, data_reg,
1699 TCG_REG_GUEST_BASE, otype, addr_reg);
1700 } else {
1701 tcg_out_qemu_st_direct(s, memop, data_reg,
1702 addr_reg, TCG_TYPE_I64, TCG_REG_XZR);
1703 }
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01001704#endif /* CONFIG_SOFTMMU */
Claudio Fontana4a136e02013-06-12 16:20:22 +01001705}
1706
Richard Henderson8587c302014-04-28 12:02:31 -07001707static tcg_insn_unit *tb_ret_addr;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001708
Claudio Fontana4a136e02013-06-12 16:20:22 +01001709static void tcg_out_op(TCGContext *s, TCGOpcode opc,
Richard Henderson8d8db192013-08-15 09:40:57 -07001710 const TCGArg args[TCG_MAX_OP_ARGS],
1711 const int const_args[TCG_MAX_OP_ARGS])
Claudio Fontana4a136e02013-06-12 16:20:22 +01001712{
Richard Hendersonf0293412013-08-15 09:11:46 -07001713 /* 99% of the time, we can signal the use of extension registers
1714 by looking to see if the opcode handles 64-bit data. */
1715 TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001716
Richard Henderson8d8db192013-08-15 09:40:57 -07001717 /* Hoist the loads of the most common arguments. */
1718 TCGArg a0 = args[0];
1719 TCGArg a1 = args[1];
1720 TCGArg a2 = args[2];
1721 int c2 = const_args[2];
1722
Richard Henderson04ce3972013-08-09 23:58:19 -04001723 /* Some operands are defined with "rZ" constraint, a register or
1724 the zero register. These need not actually test args[I] == 0. */
1725#define REG0(I) (const_args[I] ? TCG_REG_XZR : (TCGReg)args[I])
1726
Claudio Fontana4a136e02013-06-12 16:20:22 +01001727 switch (opc) {
1728 case INDEX_op_exit_tb:
Richard Hendersonb19f0c22017-04-26 08:42:58 -07001729 /* Reuse the zeroing that exists for goto_ptr. */
1730 if (a0 == 0) {
Pranith Kumar23b7aa12017-06-30 10:36:12 -04001731 tcg_out_goto_long(s, s->code_gen_epilogue);
Richard Hendersonb19f0c22017-04-26 08:42:58 -07001732 } else {
1733 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
Pranith Kumar23b7aa12017-06-30 10:36:12 -04001734 tcg_out_goto_long(s, tb_ret_addr);
Richard Hendersonb19f0c22017-04-26 08:42:58 -07001735 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001736 break;
1737
1738 case INDEX_op_goto_tb:
Pranith Kumar2acee8b2017-06-30 10:36:14 -04001739 if (s->tb_jmp_insn_offset != NULL) {
Richard Hendersona8583392017-07-31 22:02:31 -07001740 /* TCG_TARGET_HAS_direct_jump */
Pranith Kumar2acee8b2017-06-30 10:36:14 -04001741 /* Ensure that ADRP+ADD are 8-byte aligned so that an atomic
1742 write can be used to patch the target address. */
1743 if ((uintptr_t)s->code_ptr & 7) {
1744 tcg_out32(s, NOP);
1745 }
1746 s->tb_jmp_insn_offset[a0] = tcg_current_code_size(s);
1747 /* actual branch destination will be patched by
Richard Hendersona8583392017-07-31 22:02:31 -07001748 tb_target_set_jmp_target later. */
Pranith Kumar2acee8b2017-06-30 10:36:14 -04001749 tcg_out_insn(s, 3406, ADRP, TCG_REG_TMP, 0);
1750 tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_TMP, TCG_REG_TMP, 0);
1751 } else {
Richard Hendersona8583392017-07-31 22:02:31 -07001752 /* !TCG_TARGET_HAS_direct_jump */
Pranith Kumar2acee8b2017-06-30 10:36:14 -04001753 tcg_debug_assert(s->tb_jmp_target_addr != NULL);
1754 intptr_t offset = tcg_pcrel_diff(s, (s->tb_jmp_target_addr + a0)) >> 2;
1755 tcg_out_insn(s, 3305, LDR, offset, TCG_REG_TMP);
Pranith Kumarb68686b2017-06-30 10:36:13 -04001756 }
Pranith Kumarb68686b2017-06-30 10:36:13 -04001757 tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
Richard Henderson9f754622018-06-14 19:57:03 -10001758 set_jmp_reset_offset(s, a0);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001759 break;
1760
Richard Hendersonb19f0c22017-04-26 08:42:58 -07001761 case INDEX_op_goto_ptr:
1762 tcg_out_insn(s, 3207, BR, a0);
1763 break;
1764
Claudio Fontana4a136e02013-06-12 16:20:22 +01001765 case INDEX_op_br:
Richard Hendersonbec16312015-02-13 13:39:54 -08001766 tcg_out_goto_label(s, arg_label(a0));
Claudio Fontana4a136e02013-06-12 16:20:22 +01001767 break;
1768
Claudio Fontana4a136e02013-06-12 16:20:22 +01001769 case INDEX_op_ld8u_i32:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001770 case INDEX_op_ld8u_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001771 tcg_out_ldst(s, I3312_LDRB, a0, a1, a2, 0);
Richard Hendersone81864a2014-03-03 21:58:46 -05001772 break;
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001773 case INDEX_op_ld8s_i32:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001774 tcg_out_ldst(s, I3312_LDRSBW, a0, a1, a2, 0);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001775 break;
1776 case INDEX_op_ld8s_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001777 tcg_out_ldst(s, I3312_LDRSBX, a0, a1, a2, 0);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001778 break;
1779 case INDEX_op_ld16u_i32:
1780 case INDEX_op_ld16u_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001781 tcg_out_ldst(s, I3312_LDRH, a0, a1, a2, 1);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001782 break;
1783 case INDEX_op_ld16s_i32:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001784 tcg_out_ldst(s, I3312_LDRSHW, a0, a1, a2, 1);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001785 break;
1786 case INDEX_op_ld16s_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001787 tcg_out_ldst(s, I3312_LDRSHX, a0, a1, a2, 1);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001788 break;
1789 case INDEX_op_ld_i32:
1790 case INDEX_op_ld32u_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001791 tcg_out_ldst(s, I3312_LDRW, a0, a1, a2, 2);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001792 break;
1793 case INDEX_op_ld32s_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001794 tcg_out_ldst(s, I3312_LDRSWX, a0, a1, a2, 2);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001795 break;
1796 case INDEX_op_ld_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001797 tcg_out_ldst(s, I3312_LDRX, a0, a1, a2, 3);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001798 break;
1799
Claudio Fontana4a136e02013-06-12 16:20:22 +01001800 case INDEX_op_st8_i32:
1801 case INDEX_op_st8_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001802 tcg_out_ldst(s, I3312_STRB, REG0(0), a1, a2, 0);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001803 break;
Claudio Fontana4a136e02013-06-12 16:20:22 +01001804 case INDEX_op_st16_i32:
1805 case INDEX_op_st16_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001806 tcg_out_ldst(s, I3312_STRH, REG0(0), a1, a2, 1);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001807 break;
1808 case INDEX_op_st_i32:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001809 case INDEX_op_st32_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001810 tcg_out_ldst(s, I3312_STRW, REG0(0), a1, a2, 2);
Richard Hendersondc73dfd2014-03-03 16:36:01 -08001811 break;
1812 case INDEX_op_st_i64:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07001813 tcg_out_ldst(s, I3312_STRX, REG0(0), a1, a2, 3);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001814 break;
1815
Claudio Fontana4a136e02013-06-12 16:20:22 +01001816 case INDEX_op_add_i32:
Richard Henderson90f1cd92013-08-14 09:56:14 -07001817 a2 = (int32_t)a2;
1818 /* FALLTHRU */
1819 case INDEX_op_add_i64:
1820 if (c2) {
1821 tcg_out_addsubi(s, ext, a0, a1, a2);
1822 } else {
1823 tcg_out_insn(s, 3502, ADD, ext, a0, a1, a2);
1824 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001825 break;
1826
Claudio Fontana4a136e02013-06-12 16:20:22 +01001827 case INDEX_op_sub_i32:
Richard Henderson90f1cd92013-08-14 09:56:14 -07001828 a2 = (int32_t)a2;
1829 /* FALLTHRU */
1830 case INDEX_op_sub_i64:
1831 if (c2) {
1832 tcg_out_addsubi(s, ext, a0, a1, -a2);
1833 } else {
1834 tcg_out_insn(s, 3502, SUB, ext, a0, a1, a2);
1835 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001836 break;
1837
Richard Henderson14b155d2013-08-09 23:15:44 -04001838 case INDEX_op_neg_i64:
1839 case INDEX_op_neg_i32:
1840 tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1);
1841 break;
1842
Claudio Fontana4a136e02013-06-12 16:20:22 +01001843 case INDEX_op_and_i32:
Richard Hendersone029f292013-08-14 11:27:03 -07001844 a2 = (int32_t)a2;
1845 /* FALLTHRU */
1846 case INDEX_op_and_i64:
1847 if (c2) {
1848 tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, a2);
1849 } else {
1850 tcg_out_insn(s, 3510, AND, ext, a0, a1, a2);
1851 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001852 break;
1853
Richard Henderson14b155d2013-08-09 23:15:44 -04001854 case INDEX_op_andc_i32:
1855 a2 = (int32_t)a2;
1856 /* FALLTHRU */
1857 case INDEX_op_andc_i64:
1858 if (c2) {
1859 tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, ~a2);
1860 } else {
1861 tcg_out_insn(s, 3510, BIC, ext, a0, a1, a2);
1862 }
1863 break;
1864
Claudio Fontana4a136e02013-06-12 16:20:22 +01001865 case INDEX_op_or_i32:
Richard Hendersone029f292013-08-14 11:27:03 -07001866 a2 = (int32_t)a2;
1867 /* FALLTHRU */
1868 case INDEX_op_or_i64:
1869 if (c2) {
1870 tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, a2);
1871 } else {
1872 tcg_out_insn(s, 3510, ORR, ext, a0, a1, a2);
1873 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001874 break;
1875
Richard Henderson14b155d2013-08-09 23:15:44 -04001876 case INDEX_op_orc_i32:
1877 a2 = (int32_t)a2;
1878 /* FALLTHRU */
1879 case INDEX_op_orc_i64:
1880 if (c2) {
1881 tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, ~a2);
1882 } else {
1883 tcg_out_insn(s, 3510, ORN, ext, a0, a1, a2);
1884 }
1885 break;
1886
Claudio Fontana4a136e02013-06-12 16:20:22 +01001887 case INDEX_op_xor_i32:
Richard Hendersone029f292013-08-14 11:27:03 -07001888 a2 = (int32_t)a2;
1889 /* FALLTHRU */
1890 case INDEX_op_xor_i64:
1891 if (c2) {
1892 tcg_out_logicali(s, I3404_EORI, ext, a0, a1, a2);
1893 } else {
1894 tcg_out_insn(s, 3510, EOR, ext, a0, a1, a2);
1895 }
Claudio Fontana4a136e02013-06-12 16:20:22 +01001896 break;
1897
Richard Henderson14b155d2013-08-09 23:15:44 -04001898 case INDEX_op_eqv_i32:
1899 a2 = (int32_t)a2;
1900 /* FALLTHRU */
1901 case INDEX_op_eqv_i64:
1902 if (c2) {
1903 tcg_out_logicali(s, I3404_EORI, ext, a0, a1, ~a2);
1904 } else {
1905 tcg_out_insn(s, 3510, EON, ext, a0, a1, a2);
1906 }
1907 break;
1908
1909 case INDEX_op_not_i64:
1910 case INDEX_op_not_i32:
1911 tcg_out_insn(s, 3510, ORN, ext, a0, TCG_REG_XZR, a1);
1912 break;
1913
Claudio Fontana4a136e02013-06-12 16:20:22 +01001914 case INDEX_op_mul_i64:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001915 case INDEX_op_mul_i32:
Richard Henderson8678b712013-08-14 15:29:18 -07001916 tcg_out_insn(s, 3509, MADD, ext, a0, a1, a2, TCG_REG_XZR);
1917 break;
1918
1919 case INDEX_op_div_i64:
1920 case INDEX_op_div_i32:
1921 tcg_out_insn(s, 3508, SDIV, ext, a0, a1, a2);
1922 break;
1923 case INDEX_op_divu_i64:
1924 case INDEX_op_divu_i32:
1925 tcg_out_insn(s, 3508, UDIV, ext, a0, a1, a2);
1926 break;
1927
1928 case INDEX_op_rem_i64:
1929 case INDEX_op_rem_i32:
1930 tcg_out_insn(s, 3508, SDIV, ext, TCG_REG_TMP, a1, a2);
1931 tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1);
1932 break;
1933 case INDEX_op_remu_i64:
1934 case INDEX_op_remu_i32:
1935 tcg_out_insn(s, 3508, UDIV, ext, TCG_REG_TMP, a1, a2);
1936 tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP, a2, a1);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001937 break;
1938
1939 case INDEX_op_shl_i64:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001940 case INDEX_op_shl_i32:
Richard Hendersondf9351e2013-08-13 13:49:17 -07001941 if (c2) {
Richard Henderson8d8db192013-08-15 09:40:57 -07001942 tcg_out_shl(s, ext, a0, a1, a2);
Richard Hendersondf9351e2013-08-13 13:49:17 -07001943 } else {
1944 tcg_out_insn(s, 3508, LSLV, ext, a0, a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001945 }
1946 break;
1947
1948 case INDEX_op_shr_i64:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001949 case INDEX_op_shr_i32:
Richard Hendersondf9351e2013-08-13 13:49:17 -07001950 if (c2) {
Richard Henderson8d8db192013-08-15 09:40:57 -07001951 tcg_out_shr(s, ext, a0, a1, a2);
Richard Hendersondf9351e2013-08-13 13:49:17 -07001952 } else {
1953 tcg_out_insn(s, 3508, LSRV, ext, a0, a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001954 }
1955 break;
1956
1957 case INDEX_op_sar_i64:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001958 case INDEX_op_sar_i32:
Richard Hendersondf9351e2013-08-13 13:49:17 -07001959 if (c2) {
Richard Henderson8d8db192013-08-15 09:40:57 -07001960 tcg_out_sar(s, ext, a0, a1, a2);
Richard Hendersondf9351e2013-08-13 13:49:17 -07001961 } else {
1962 tcg_out_insn(s, 3508, ASRV, ext, a0, a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001963 }
1964 break;
1965
1966 case INDEX_op_rotr_i64:
Claudio Fontana4a136e02013-06-12 16:20:22 +01001967 case INDEX_op_rotr_i32:
Richard Hendersondf9351e2013-08-13 13:49:17 -07001968 if (c2) {
Richard Henderson8d8db192013-08-15 09:40:57 -07001969 tcg_out_rotr(s, ext, a0, a1, a2);
Richard Hendersondf9351e2013-08-13 13:49:17 -07001970 } else {
1971 tcg_out_insn(s, 3508, RORV, ext, a0, a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001972 }
1973 break;
1974
1975 case INDEX_op_rotl_i64:
Richard Hendersondf9351e2013-08-13 13:49:17 -07001976 case INDEX_op_rotl_i32:
1977 if (c2) {
Richard Henderson8d8db192013-08-15 09:40:57 -07001978 tcg_out_rotl(s, ext, a0, a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001979 } else {
Richard Henderson50573c62013-08-13 12:10:08 -07001980 tcg_out_insn(s, 3502, SUB, 0, TCG_REG_TMP, TCG_REG_XZR, a2);
Richard Hendersondf9351e2013-08-13 13:49:17 -07001981 tcg_out_insn(s, 3508, RORV, ext, a0, a1, TCG_REG_TMP);
Claudio Fontana4a136e02013-06-12 16:20:22 +01001982 }
1983 break;
1984
Richard Henderson53c76c12016-11-16 14:03:28 +01001985 case INDEX_op_clz_i64:
1986 case INDEX_op_clz_i32:
1987 tcg_out_cltz(s, ext, a0, a1, a2, c2, false);
1988 break;
1989 case INDEX_op_ctz_i64:
1990 case INDEX_op_ctz_i32:
1991 tcg_out_cltz(s, ext, a0, a1, a2, c2, true);
1992 break;
1993
Richard Henderson8d8db192013-08-15 09:40:57 -07001994 case INDEX_op_brcond_i32:
Richard Henderson90f1cd92013-08-14 09:56:14 -07001995 a1 = (int32_t)a1;
1996 /* FALLTHRU */
1997 case INDEX_op_brcond_i64:
Richard Hendersonbec16312015-02-13 13:39:54 -08001998 tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3]));
Claudio Fontana4a136e02013-06-12 16:20:22 +01001999 break;
2000
Claudio Fontana4a136e02013-06-12 16:20:22 +01002001 case INDEX_op_setcond_i32:
Richard Henderson90f1cd92013-08-14 09:56:14 -07002002 a2 = (int32_t)a2;
2003 /* FALLTHRU */
2004 case INDEX_op_setcond_i64:
2005 tcg_out_cmp(s, ext, a1, a2, c2);
Richard Hendersoned7a0aa2013-09-11 18:54:46 -07002006 /* Use CSET alias of CSINC Wd, WZR, WZR, invert(cond). */
2007 tcg_out_insn(s, 3506, CSINC, TCG_TYPE_I32, a0, TCG_REG_XZR,
2008 TCG_REG_XZR, tcg_invert_cond(args[3]));
Claudio Fontana4a136e02013-06-12 16:20:22 +01002009 break;
2010
Richard Henderson04ce3972013-08-09 23:58:19 -04002011 case INDEX_op_movcond_i32:
2012 a2 = (int32_t)a2;
2013 /* FALLTHRU */
2014 case INDEX_op_movcond_i64:
2015 tcg_out_cmp(s, ext, a1, a2, c2);
2016 tcg_out_insn(s, 3506, CSEL, ext, a0, REG0(3), REG0(4), args[5]);
2017 break;
2018
Richard Hendersonde61d142014-02-27 14:42:18 -05002019 case INDEX_op_qemu_ld_i32:
2020 case INDEX_op_qemu_ld_i64:
Richard Henderson59227d52015-05-12 11:51:44 -07002021 tcg_out_qemu_ld(s, a0, a1, a2, ext);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002022 break;
Richard Hendersonde61d142014-02-27 14:42:18 -05002023 case INDEX_op_qemu_st_i32:
2024 case INDEX_op_qemu_st_i64:
Richard Henderson59227d52015-05-12 11:51:44 -07002025 tcg_out_qemu_st(s, REG0(0), a1, a2);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002026 break;
2027
Richard Hendersonf0293412013-08-15 09:11:46 -07002028 case INDEX_op_bswap64_i64:
Richard Hendersonedd88242014-03-03 16:21:27 -08002029 tcg_out_rev64(s, a0, a1);
2030 break;
2031 case INDEX_op_bswap32_i64:
Claudio Fontana9c4a0592013-06-12 16:20:23 +01002032 case INDEX_op_bswap32_i32:
Richard Hendersonedd88242014-03-03 16:21:27 -08002033 tcg_out_rev32(s, a0, a1);
Claudio Fontana9c4a0592013-06-12 16:20:23 +01002034 break;
2035 case INDEX_op_bswap16_i64:
2036 case INDEX_op_bswap16_i32:
Richard Hendersonedd88242014-03-03 16:21:27 -08002037 tcg_out_rev16(s, a0, a1);
Claudio Fontana9c4a0592013-06-12 16:20:23 +01002038 break;
2039
Claudio Fontana31f12752013-06-12 16:20:23 +01002040 case INDEX_op_ext8s_i64:
Claudio Fontana31f12752013-06-12 16:20:23 +01002041 case INDEX_op_ext8s_i32:
Richard Henderson929f8b52014-03-03 16:12:21 -08002042 tcg_out_sxt(s, ext, MO_8, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002043 break;
2044 case INDEX_op_ext16s_i64:
Claudio Fontana31f12752013-06-12 16:20:23 +01002045 case INDEX_op_ext16s_i32:
Richard Henderson929f8b52014-03-03 16:12:21 -08002046 tcg_out_sxt(s, ext, MO_16, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002047 break;
Aurelien Jarno4f2331e2015-07-27 12:41:45 +02002048 case INDEX_op_ext_i32_i64:
Claudio Fontana31f12752013-06-12 16:20:23 +01002049 case INDEX_op_ext32s_i64:
Richard Henderson929f8b52014-03-03 16:12:21 -08002050 tcg_out_sxt(s, TCG_TYPE_I64, MO_32, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002051 break;
2052 case INDEX_op_ext8u_i64:
2053 case INDEX_op_ext8u_i32:
Richard Henderson929f8b52014-03-03 16:12:21 -08002054 tcg_out_uxt(s, MO_8, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002055 break;
2056 case INDEX_op_ext16u_i64:
2057 case INDEX_op_ext16u_i32:
Richard Henderson929f8b52014-03-03 16:12:21 -08002058 tcg_out_uxt(s, MO_16, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002059 break;
Aurelien Jarno4f2331e2015-07-27 12:41:45 +02002060 case INDEX_op_extu_i32_i64:
Claudio Fontana31f12752013-06-12 16:20:23 +01002061 case INDEX_op_ext32u_i64:
Richard Henderson929f8b52014-03-03 16:12:21 -08002062 tcg_out_movr(s, TCG_TYPE_I32, a0, a1);
Claudio Fontana31f12752013-06-12 16:20:23 +01002063 break;
2064
Richard Hendersonb3c56df2013-08-14 13:05:07 -07002065 case INDEX_op_deposit_i64:
2066 case INDEX_op_deposit_i32:
2067 tcg_out_dep(s, ext, a0, REG0(2), args[3], args[4]);
2068 break;
2069
Richard Hendersone2179f92016-10-14 13:20:49 -05002070 case INDEX_op_extract_i64:
2071 case INDEX_op_extract_i32:
2072 tcg_out_ubfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
2073 break;
2074
2075 case INDEX_op_sextract_i64:
2076 case INDEX_op_sextract_i32:
2077 tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1);
2078 break;
2079
Richard Henderson464c2962019-02-25 13:25:46 -08002080 case INDEX_op_extract2_i64:
2081 case INDEX_op_extract2_i32:
2082 tcg_out_extr(s, ext, a0, a1, a2, args[3]);
2083 break;
2084
Richard Hendersonc6e929e2013-08-14 13:30:07 -07002085 case INDEX_op_add2_i32:
2086 tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3),
2087 (int32_t)args[4], args[5], const_args[4],
2088 const_args[5], false);
2089 break;
2090 case INDEX_op_add2_i64:
2091 tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4],
2092 args[5], const_args[4], const_args[5], false);
2093 break;
2094 case INDEX_op_sub2_i32:
2095 tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, REG0(2), REG0(3),
2096 (int32_t)args[4], args[5], const_args[4],
2097 const_args[5], true);
2098 break;
2099 case INDEX_op_sub2_i64:
2100 tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, REG0(2), REG0(3), args[4],
2101 args[5], const_args[4], const_args[5], true);
2102 break;
2103
Richard Henderson1fcc9dd2013-08-14 15:03:27 -07002104 case INDEX_op_muluh_i64:
2105 tcg_out_insn(s, 3508, UMULH, TCG_TYPE_I64, a0, a1, a2);
2106 break;
2107 case INDEX_op_mulsh_i64:
2108 tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2);
2109 break;
2110
Pranith Kumarc7a59c22016-07-14 16:20:15 -04002111 case INDEX_op_mb:
2112 tcg_out_mb(s, a0);
2113 break;
2114
Richard Henderson96d0ee72014-04-25 15:19:33 -04002115 case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
Richard Hendersona51a6b62013-08-15 11:13:06 -07002116 case INDEX_op_mov_i64:
Richard Henderson96d0ee72014-04-25 15:19:33 -04002117 case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */
Richard Hendersona51a6b62013-08-15 11:13:06 -07002118 case INDEX_op_movi_i64:
Richard Henderson96d0ee72014-04-25 15:19:33 -04002119 case INDEX_op_call: /* Always emitted via tcg_out_call. */
Claudio Fontana4a136e02013-06-12 16:20:22 +01002120 default:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002121 g_assert_not_reached();
Claudio Fontana4a136e02013-06-12 16:20:22 +01002122 }
Richard Henderson04ce3972013-08-09 23:58:19 -04002123
2124#undef REG0
Claudio Fontana4a136e02013-06-12 16:20:22 +01002125}
2126
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002127static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc,
2128 unsigned vecl, unsigned vece,
2129 const TCGArg *args, const int *const_args)
2130{
2131 static const AArch64Insn cmp_insn[16] = {
2132 [TCG_COND_EQ] = I3616_CMEQ,
2133 [TCG_COND_GT] = I3616_CMGT,
2134 [TCG_COND_GE] = I3616_CMGE,
2135 [TCG_COND_GTU] = I3616_CMHI,
2136 [TCG_COND_GEU] = I3616_CMHS,
2137 };
2138 static const AArch64Insn cmp0_insn[16] = {
2139 [TCG_COND_EQ] = I3617_CMEQ0,
2140 [TCG_COND_GT] = I3617_CMGT0,
2141 [TCG_COND_GE] = I3617_CMGE0,
2142 [TCG_COND_LT] = I3617_CMLT0,
2143 [TCG_COND_LE] = I3617_CMLE0,
2144 };
2145
2146 TCGType type = vecl + TCG_TYPE_V64;
2147 unsigned is_q = vecl;
2148 TCGArg a0, a1, a2;
2149
2150 a0 = args[0];
2151 a1 = args[1];
2152 a2 = args[2];
2153
2154 switch (opc) {
2155 case INDEX_op_ld_vec:
2156 tcg_out_ld(s, type, a0, a1, a2);
2157 break;
2158 case INDEX_op_st_vec:
2159 tcg_out_st(s, type, a0, a1, a2);
2160 break;
2161 case INDEX_op_add_vec:
2162 tcg_out_insn(s, 3616, ADD, is_q, vece, a0, a1, a2);
2163 break;
2164 case INDEX_op_sub_vec:
2165 tcg_out_insn(s, 3616, SUB, is_q, vece, a0, a1, a2);
2166 break;
2167 case INDEX_op_mul_vec:
2168 tcg_out_insn(s, 3616, MUL, is_q, vece, a0, a1, a2);
2169 break;
2170 case INDEX_op_neg_vec:
2171 tcg_out_insn(s, 3617, NEG, is_q, vece, a0, a1);
2172 break;
2173 case INDEX_op_and_vec:
2174 tcg_out_insn(s, 3616, AND, is_q, 0, a0, a1, a2);
2175 break;
2176 case INDEX_op_or_vec:
2177 tcg_out_insn(s, 3616, ORR, is_q, 0, a0, a1, a2);
2178 break;
2179 case INDEX_op_xor_vec:
2180 tcg_out_insn(s, 3616, EOR, is_q, 0, a0, a1, a2);
2181 break;
2182 case INDEX_op_andc_vec:
2183 tcg_out_insn(s, 3616, BIC, is_q, 0, a0, a1, a2);
2184 break;
2185 case INDEX_op_orc_vec:
2186 tcg_out_insn(s, 3616, ORN, is_q, 0, a0, a1, a2);
2187 break;
Richard Hendersond32648d2018-12-18 07:14:23 +00002188 case INDEX_op_ssadd_vec:
2189 tcg_out_insn(s, 3616, SQADD, is_q, vece, a0, a1, a2);
2190 break;
2191 case INDEX_op_sssub_vec:
2192 tcg_out_insn(s, 3616, SQSUB, is_q, vece, a0, a1, a2);
2193 break;
2194 case INDEX_op_usadd_vec:
2195 tcg_out_insn(s, 3616, UQADD, is_q, vece, a0, a1, a2);
2196 break;
2197 case INDEX_op_ussub_vec:
2198 tcg_out_insn(s, 3616, UQSUB, is_q, vece, a0, a1, a2);
2199 break;
Richard Henderson93f332a2018-12-18 07:27:06 +00002200 case INDEX_op_smax_vec:
2201 tcg_out_insn(s, 3616, SMAX, is_q, vece, a0, a1, a2);
2202 break;
2203 case INDEX_op_smin_vec:
2204 tcg_out_insn(s, 3616, SMIN, is_q, vece, a0, a1, a2);
2205 break;
2206 case INDEX_op_umax_vec:
2207 tcg_out_insn(s, 3616, UMAX, is_q, vece, a0, a1, a2);
2208 break;
2209 case INDEX_op_umin_vec:
2210 tcg_out_insn(s, 3616, UMIN, is_q, vece, a0, a1, a2);
2211 break;
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002212 case INDEX_op_not_vec:
2213 tcg_out_insn(s, 3617, NOT, is_q, 0, a0, a1);
2214 break;
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002215 case INDEX_op_shli_vec:
2216 tcg_out_insn(s, 3614, SHL, is_q, a0, a1, a2 + (8 << vece));
2217 break;
2218 case INDEX_op_shri_vec:
2219 tcg_out_insn(s, 3614, USHR, is_q, a0, a1, (16 << vece) - a2);
2220 break;
2221 case INDEX_op_sari_vec:
2222 tcg_out_insn(s, 3614, SSHR, is_q, a0, a1, (16 << vece) - a2);
2223 break;
2224 case INDEX_op_cmp_vec:
2225 {
2226 TCGCond cond = args[3];
2227 AArch64Insn insn;
2228
2229 if (cond == TCG_COND_NE) {
2230 if (const_args[2]) {
2231 tcg_out_insn(s, 3616, CMTST, is_q, vece, a0, a1, a1);
2232 } else {
2233 tcg_out_insn(s, 3616, CMEQ, is_q, vece, a0, a1, a2);
2234 tcg_out_insn(s, 3617, NOT, is_q, 0, a0, a0);
2235 }
2236 } else {
2237 if (const_args[2]) {
2238 insn = cmp0_insn[cond];
2239 if (insn) {
2240 tcg_out_insn_3617(s, insn, is_q, vece, a0, a1);
2241 break;
2242 }
2243 tcg_out_dupi_vec(s, type, TCG_VEC_TMP, 0);
2244 a2 = TCG_VEC_TMP;
2245 }
2246 insn = cmp_insn[cond];
2247 if (insn == 0) {
2248 TCGArg t;
2249 t = a1, a1 = a2, a2 = t;
2250 cond = tcg_swap_cond(cond);
2251 insn = cmp_insn[cond];
2252 tcg_debug_assert(insn != 0);
2253 }
2254 tcg_out_insn_3616(s, insn, is_q, vece, a0, a1, a2);
2255 }
2256 }
2257 break;
Richard Hendersonbab16712019-03-18 11:20:27 -07002258
2259 case INDEX_op_mov_vec: /* Always emitted via tcg_out_mov. */
2260 case INDEX_op_dupi_vec: /* Always emitted via tcg_out_movi. */
2261 case INDEX_op_dup_vec: /* Always emitted via tcg_out_dup_vec. */
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002262 default:
2263 g_assert_not_reached();
2264 }
2265}
2266
2267int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece)
2268{
2269 switch (opc) {
2270 case INDEX_op_add_vec:
2271 case INDEX_op_sub_vec:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002272 case INDEX_op_and_vec:
2273 case INDEX_op_or_vec:
2274 case INDEX_op_xor_vec:
2275 case INDEX_op_andc_vec:
2276 case INDEX_op_orc_vec:
2277 case INDEX_op_neg_vec:
2278 case INDEX_op_not_vec:
2279 case INDEX_op_cmp_vec:
2280 case INDEX_op_shli_vec:
2281 case INDEX_op_shri_vec:
2282 case INDEX_op_sari_vec:
Richard Hendersond32648d2018-12-18 07:14:23 +00002283 case INDEX_op_ssadd_vec:
2284 case INDEX_op_sssub_vec:
2285 case INDEX_op_usadd_vec:
2286 case INDEX_op_ussub_vec:
Richard Henderson93f332a2018-12-18 07:27:06 +00002287 case INDEX_op_smax_vec:
2288 case INDEX_op_smin_vec:
2289 case INDEX_op_umax_vec:
2290 case INDEX_op_umin_vec:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002291 return 1;
Alex Bennéee65a5f22018-07-19 16:42:48 +01002292 case INDEX_op_mul_vec:
2293 return vece < MO_64;
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002294
2295 default:
2296 return 0;
2297 }
2298}
2299
2300void tcg_expand_vec_op(TCGOpcode opc, TCGType type, unsigned vece,
2301 TCGArg a0, ...)
2302{
2303}
2304
Richard Hendersonf69d2772016-11-18 09:31:40 +01002305static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
2306{
Richard Henderson1897cc22017-09-11 10:27:34 -07002307 static const TCGTargetOpDef r = { .args_ct_str = { "r" } };
2308 static const TCGTargetOpDef r_r = { .args_ct_str = { "r", "r" } };
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002309 static const TCGTargetOpDef w_w = { .args_ct_str = { "w", "w" } };
2310 static const TCGTargetOpDef w_r = { .args_ct_str = { "w", "r" } };
2311 static const TCGTargetOpDef w_wr = { .args_ct_str = { "w", "wr" } };
Richard Henderson1897cc22017-09-11 10:27:34 -07002312 static const TCGTargetOpDef r_l = { .args_ct_str = { "r", "l" } };
2313 static const TCGTargetOpDef r_rA = { .args_ct_str = { "r", "rA" } };
2314 static const TCGTargetOpDef rZ_r = { .args_ct_str = { "rZ", "r" } };
2315 static const TCGTargetOpDef lZ_l = { .args_ct_str = { "lZ", "l" } };
2316 static const TCGTargetOpDef r_r_r = { .args_ct_str = { "r", "r", "r" } };
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002317 static const TCGTargetOpDef w_w_w = { .args_ct_str = { "w", "w", "w" } };
2318 static const TCGTargetOpDef w_w_wZ = { .args_ct_str = { "w", "w", "wZ" } };
Richard Henderson1897cc22017-09-11 10:27:34 -07002319 static const TCGTargetOpDef r_r_ri = { .args_ct_str = { "r", "r", "ri" } };
2320 static const TCGTargetOpDef r_r_rA = { .args_ct_str = { "r", "r", "rA" } };
2321 static const TCGTargetOpDef r_r_rL = { .args_ct_str = { "r", "r", "rL" } };
2322 static const TCGTargetOpDef r_r_rAL
2323 = { .args_ct_str = { "r", "r", "rAL" } };
2324 static const TCGTargetOpDef dep
2325 = { .args_ct_str = { "r", "0", "rZ" } };
Richard Henderson464c2962019-02-25 13:25:46 -08002326 static const TCGTargetOpDef ext2
2327 = { .args_ct_str = { "r", "rZ", "rZ" } };
Richard Henderson1897cc22017-09-11 10:27:34 -07002328 static const TCGTargetOpDef movc
2329 = { .args_ct_str = { "r", "r", "rA", "rZ", "rZ" } };
2330 static const TCGTargetOpDef add2
2331 = { .args_ct_str = { "r", "r", "rZ", "rZ", "rA", "rMZ" } };
Richard Hendersonf69d2772016-11-18 09:31:40 +01002332
Richard Henderson1897cc22017-09-11 10:27:34 -07002333 switch (op) {
2334 case INDEX_op_goto_ptr:
2335 return &r;
2336
2337 case INDEX_op_ld8u_i32:
2338 case INDEX_op_ld8s_i32:
2339 case INDEX_op_ld16u_i32:
2340 case INDEX_op_ld16s_i32:
2341 case INDEX_op_ld_i32:
2342 case INDEX_op_ld8u_i64:
2343 case INDEX_op_ld8s_i64:
2344 case INDEX_op_ld16u_i64:
2345 case INDEX_op_ld16s_i64:
2346 case INDEX_op_ld32u_i64:
2347 case INDEX_op_ld32s_i64:
2348 case INDEX_op_ld_i64:
2349 case INDEX_op_neg_i32:
2350 case INDEX_op_neg_i64:
2351 case INDEX_op_not_i32:
2352 case INDEX_op_not_i64:
2353 case INDEX_op_bswap16_i32:
2354 case INDEX_op_bswap32_i32:
2355 case INDEX_op_bswap16_i64:
2356 case INDEX_op_bswap32_i64:
2357 case INDEX_op_bswap64_i64:
2358 case INDEX_op_ext8s_i32:
2359 case INDEX_op_ext16s_i32:
2360 case INDEX_op_ext8u_i32:
2361 case INDEX_op_ext16u_i32:
2362 case INDEX_op_ext8s_i64:
2363 case INDEX_op_ext16s_i64:
2364 case INDEX_op_ext32s_i64:
2365 case INDEX_op_ext8u_i64:
2366 case INDEX_op_ext16u_i64:
2367 case INDEX_op_ext32u_i64:
2368 case INDEX_op_ext_i32_i64:
2369 case INDEX_op_extu_i32_i64:
2370 case INDEX_op_extract_i32:
2371 case INDEX_op_extract_i64:
2372 case INDEX_op_sextract_i32:
2373 case INDEX_op_sextract_i64:
2374 return &r_r;
2375
2376 case INDEX_op_st8_i32:
2377 case INDEX_op_st16_i32:
2378 case INDEX_op_st_i32:
2379 case INDEX_op_st8_i64:
2380 case INDEX_op_st16_i64:
2381 case INDEX_op_st32_i64:
2382 case INDEX_op_st_i64:
2383 return &rZ_r;
2384
2385 case INDEX_op_add_i32:
2386 case INDEX_op_add_i64:
2387 case INDEX_op_sub_i32:
2388 case INDEX_op_sub_i64:
2389 case INDEX_op_setcond_i32:
2390 case INDEX_op_setcond_i64:
2391 return &r_r_rA;
2392
2393 case INDEX_op_mul_i32:
2394 case INDEX_op_mul_i64:
2395 case INDEX_op_div_i32:
2396 case INDEX_op_div_i64:
2397 case INDEX_op_divu_i32:
2398 case INDEX_op_divu_i64:
2399 case INDEX_op_rem_i32:
2400 case INDEX_op_rem_i64:
2401 case INDEX_op_remu_i32:
2402 case INDEX_op_remu_i64:
2403 case INDEX_op_muluh_i64:
2404 case INDEX_op_mulsh_i64:
2405 return &r_r_r;
2406
2407 case INDEX_op_and_i32:
2408 case INDEX_op_and_i64:
2409 case INDEX_op_or_i32:
2410 case INDEX_op_or_i64:
2411 case INDEX_op_xor_i32:
2412 case INDEX_op_xor_i64:
2413 case INDEX_op_andc_i32:
2414 case INDEX_op_andc_i64:
2415 case INDEX_op_orc_i32:
2416 case INDEX_op_orc_i64:
2417 case INDEX_op_eqv_i32:
2418 case INDEX_op_eqv_i64:
2419 return &r_r_rL;
2420
2421 case INDEX_op_shl_i32:
2422 case INDEX_op_shr_i32:
2423 case INDEX_op_sar_i32:
2424 case INDEX_op_rotl_i32:
2425 case INDEX_op_rotr_i32:
2426 case INDEX_op_shl_i64:
2427 case INDEX_op_shr_i64:
2428 case INDEX_op_sar_i64:
2429 case INDEX_op_rotl_i64:
2430 case INDEX_op_rotr_i64:
2431 return &r_r_ri;
2432
2433 case INDEX_op_clz_i32:
2434 case INDEX_op_ctz_i32:
2435 case INDEX_op_clz_i64:
2436 case INDEX_op_ctz_i64:
2437 return &r_r_rAL;
2438
2439 case INDEX_op_brcond_i32:
2440 case INDEX_op_brcond_i64:
2441 return &r_rA;
2442
2443 case INDEX_op_movcond_i32:
2444 case INDEX_op_movcond_i64:
2445 return &movc;
2446
2447 case INDEX_op_qemu_ld_i32:
2448 case INDEX_op_qemu_ld_i64:
2449 return &r_l;
2450 case INDEX_op_qemu_st_i32:
2451 case INDEX_op_qemu_st_i64:
2452 return &lZ_l;
2453
2454 case INDEX_op_deposit_i32:
2455 case INDEX_op_deposit_i64:
2456 return &dep;
2457
Richard Henderson464c2962019-02-25 13:25:46 -08002458 case INDEX_op_extract2_i32:
2459 case INDEX_op_extract2_i64:
2460 return &ext2;
2461
Richard Henderson1897cc22017-09-11 10:27:34 -07002462 case INDEX_op_add2_i32:
2463 case INDEX_op_add2_i64:
2464 case INDEX_op_sub2_i32:
2465 case INDEX_op_sub2_i64:
2466 return &add2;
2467
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002468 case INDEX_op_add_vec:
2469 case INDEX_op_sub_vec:
2470 case INDEX_op_mul_vec:
2471 case INDEX_op_and_vec:
2472 case INDEX_op_or_vec:
2473 case INDEX_op_xor_vec:
2474 case INDEX_op_andc_vec:
2475 case INDEX_op_orc_vec:
Richard Hendersond32648d2018-12-18 07:14:23 +00002476 case INDEX_op_ssadd_vec:
2477 case INDEX_op_sssub_vec:
2478 case INDEX_op_usadd_vec:
2479 case INDEX_op_ussub_vec:
Richard Henderson93f332a2018-12-18 07:27:06 +00002480 case INDEX_op_smax_vec:
2481 case INDEX_op_smin_vec:
2482 case INDEX_op_umax_vec:
2483 case INDEX_op_umin_vec:
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002484 return &w_w_w;
2485 case INDEX_op_not_vec:
2486 case INDEX_op_neg_vec:
2487 case INDEX_op_shli_vec:
2488 case INDEX_op_shri_vec:
2489 case INDEX_op_sari_vec:
2490 return &w_w;
2491 case INDEX_op_ld_vec:
2492 case INDEX_op_st_vec:
2493 return &w_r;
2494 case INDEX_op_dup_vec:
2495 return &w_wr;
2496 case INDEX_op_cmp_vec:
2497 return &w_w_wZ;
2498
Richard Henderson1897cc22017-09-11 10:27:34 -07002499 default:
2500 return NULL;
Richard Hendersonf69d2772016-11-18 09:31:40 +01002501 }
Richard Hendersonf69d2772016-11-18 09:31:40 +01002502}
2503
Claudio Fontana4a136e02013-06-12 16:20:22 +01002504static void tcg_target_init(TCGContext *s)
2505{
Richard Hendersonf46934d2017-09-11 12:44:30 -07002506 tcg_target_available_regs[TCG_TYPE_I32] = 0xffffffffu;
2507 tcg_target_available_regs[TCG_TYPE_I64] = 0xffffffffu;
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002508 tcg_target_available_regs[TCG_TYPE_V64] = 0xffffffff00000000ull;
2509 tcg_target_available_regs[TCG_TYPE_V128] = 0xffffffff00000000ull;
Claudio Fontana4a136e02013-06-12 16:20:22 +01002510
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002511 tcg_target_call_clobber_regs = -1ull;
Richard Hendersonf46934d2017-09-11 12:44:30 -07002512 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X19);
2513 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X20);
2514 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X21);
2515 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X22);
2516 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X23);
2517 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X24);
2518 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X25);
2519 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X26);
2520 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X27);
2521 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X28);
2522 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_X29);
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002523 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V8);
2524 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V9);
2525 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V10);
2526 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V11);
2527 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V12);
2528 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V13);
2529 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V14);
2530 tcg_regset_reset_reg(tcg_target_call_clobber_regs, TCG_REG_V15);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002531
Richard Hendersonccb1bb62017-09-11 11:25:55 -07002532 s->reserved_regs = 0;
Claudio Fontana4a136e02013-06-12 16:20:22 +01002533 tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
2534 tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP);
2535 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
2536 tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */
Richard Henderson14e4c1e2017-09-11 22:09:28 -07002537 tcg_regset_set_reg(s->reserved_regs, TCG_VEC_TMP);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002538}
2539
Richard Henderson38d195a2014-03-14 21:33:29 -04002540/* Saving pairs: (X19, X20) .. (X27, X28), (X29(fp), X30(lr)). */
2541#define PUSH_SIZE ((30 - 19 + 1) * 8)
2542
2543#define FRAME_SIZE \
2544 ((PUSH_SIZE \
2545 + TCG_STATIC_CALL_ARGS_SIZE \
2546 + CPU_TEMP_BUF_NLONGS * sizeof(long) \
2547 + TCG_TARGET_STACK_ALIGN - 1) \
2548 & ~(TCG_TARGET_STACK_ALIGN - 1))
2549
2550/* We're expecting a 2 byte uleb128 encoded value. */
2551QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
2552
2553/* We're expecting to use a single ADDI insn. */
2554QEMU_BUILD_BUG_ON(FRAME_SIZE - PUSH_SIZE > 0xfff);
2555
Claudio Fontana4a136e02013-06-12 16:20:22 +01002556static void tcg_target_qemu_prologue(TCGContext *s)
2557{
Claudio Fontana4a136e02013-06-12 16:20:22 +01002558 TCGReg r;
2559
Richard Henderson95f72aa2013-08-15 13:34:47 -07002560 /* Push (FP, LR) and allocate space for all saved registers. */
2561 tcg_out_insn(s, 3314, STP, TCG_REG_FP, TCG_REG_LR,
Richard Henderson38d195a2014-03-14 21:33:29 -04002562 TCG_REG_SP, -PUSH_SIZE, 1, 1);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002563
Richard Hendersond82b78e2013-08-15 12:54:28 -07002564 /* Set up frame pointer for canonical unwinding. */
Richard Henderson929f8b52014-03-03 16:12:21 -08002565 tcg_out_movr_sp(s, TCG_TYPE_I64, TCG_REG_FP, TCG_REG_SP);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002566
Richard Hendersond82b78e2013-08-15 12:54:28 -07002567 /* Store callee-preserved regs x19..x28. */
Claudio Fontana4a136e02013-06-12 16:20:22 +01002568 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
Richard Henderson95f72aa2013-08-15 13:34:47 -07002569 int ofs = (r - TCG_REG_X19 + 2) * 8;
2570 tcg_out_insn(s, 3314, STP, r, r + 1, TCG_REG_SP, ofs, 1, 0);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002571 }
2572
Richard Henderson096c46c2013-08-13 14:37:08 -07002573 /* Make stack space for TCG locals. */
2574 tcg_out_insn(s, 3401, SUBI, TCG_TYPE_I64, TCG_REG_SP, TCG_REG_SP,
Richard Henderson38d195a2014-03-14 21:33:29 -04002575 FRAME_SIZE - PUSH_SIZE);
Richard Henderson096c46c2013-08-13 14:37:08 -07002576
Richard Henderson95f72aa2013-08-15 13:34:47 -07002577 /* Inform TCG about how to find TCG locals with register, offset, size. */
Claudio Fontana4a136e02013-06-12 16:20:22 +01002578 tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE,
2579 CPU_TEMP_BUF_NLONGS * sizeof(long));
2580
Laurent Vivier4cbea592015-08-24 01:42:07 +02002581#if !defined(CONFIG_SOFTMMU)
Richard Henderson352bcb02015-09-01 15:58:02 -04002582 if (USE_GUEST_BASE) {
Laurent Vivierb76f21a2015-08-24 14:53:54 +02002583 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base);
Jani Kokkonen6a91c7c2013-06-12 16:20:23 +01002584 tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE);
2585 }
2586#endif
2587
Claudio Fontana4a136e02013-06-12 16:20:22 +01002588 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
Richard Henderson81d8a5e2013-08-14 20:05:51 -07002589 tcg_out_insn(s, 3207, BR, tcg_target_call_iarg_regs[1]);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002590
Richard Hendersonb19f0c22017-04-26 08:42:58 -07002591 /*
2592 * Return path for goto_ptr. Set return value to 0, a-la exit_tb,
2593 * and fall through to the rest of the epilogue.
2594 */
2595 s->code_gen_epilogue = s->code_ptr;
2596 tcg_out_movi(s, TCG_TYPE_REG, TCG_REG_X0, 0);
2597
2598 /* TB epilogue */
Claudio Fontana4a136e02013-06-12 16:20:22 +01002599 tb_ret_addr = s->code_ptr;
2600
Richard Henderson096c46c2013-08-13 14:37:08 -07002601 /* Remove TCG locals stack space. */
2602 tcg_out_insn(s, 3401, ADDI, TCG_TYPE_I64, TCG_REG_SP, TCG_REG_SP,
Richard Henderson38d195a2014-03-14 21:33:29 -04002603 FRAME_SIZE - PUSH_SIZE);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002604
Richard Henderson95f72aa2013-08-15 13:34:47 -07002605 /* Restore registers x19..x28. */
Claudio Fontana4a136e02013-06-12 16:20:22 +01002606 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
Richard Henderson95f72aa2013-08-15 13:34:47 -07002607 int ofs = (r - TCG_REG_X19 + 2) * 8;
2608 tcg_out_insn(s, 3314, LDP, r, r + 1, TCG_REG_SP, ofs, 1, 0);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002609 }
2610
Richard Henderson95f72aa2013-08-15 13:34:47 -07002611 /* Pop (FP, LR), restore SP to previous frame. */
2612 tcg_out_insn(s, 3314, LDP, TCG_REG_FP, TCG_REG_LR,
Richard Henderson38d195a2014-03-14 21:33:29 -04002613 TCG_REG_SP, PUSH_SIZE, 0, 1);
Richard Henderson81d8a5e2013-08-14 20:05:51 -07002614 tcg_out_insn(s, 3207, RET, TCG_REG_LR);
Claudio Fontana4a136e02013-06-12 16:20:22 +01002615}
Richard Henderson38d195a2014-03-14 21:33:29 -04002616
Richard Henderson55129952017-07-26 00:29:49 -07002617static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
2618{
2619 int i;
2620 for (i = 0; i < count; ++i) {
2621 p[i] = NOP;
2622 }
2623}
2624
Richard Henderson38d195a2014-03-14 21:33:29 -04002625typedef struct {
Richard Henderson3d9bddb2014-05-15 12:49:13 -07002626 DebugFrameHeader h;
Richard Henderson38d195a2014-03-14 21:33:29 -04002627 uint8_t fde_def_cfa[4];
2628 uint8_t fde_reg_ofs[24];
2629} DebugFrame;
2630
2631#define ELF_HOST_MACHINE EM_AARCH64
2632
Richard Henderson3d9bddb2014-05-15 12:49:13 -07002633static const DebugFrame debug_frame = {
2634 .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
2635 .h.cie.id = -1,
2636 .h.cie.version = 1,
2637 .h.cie.code_align = 1,
2638 .h.cie.data_align = 0x78, /* sleb128 -8 */
2639 .h.cie.return_column = TCG_REG_LR,
Richard Henderson38d195a2014-03-14 21:33:29 -04002640
2641 /* Total FDE size does not include the "len" member. */
Richard Henderson3d9bddb2014-05-15 12:49:13 -07002642 .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
Richard Henderson38d195a2014-03-14 21:33:29 -04002643
2644 .fde_def_cfa = {
2645 12, TCG_REG_SP, /* DW_CFA_def_cfa sp, ... */
2646 (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
2647 (FRAME_SIZE >> 7)
2648 },
2649 .fde_reg_ofs = {
2650 0x80 + 28, 1, /* DW_CFA_offset, x28, -8 */
2651 0x80 + 27, 2, /* DW_CFA_offset, x27, -16 */
2652 0x80 + 26, 3, /* DW_CFA_offset, x26, -24 */
2653 0x80 + 25, 4, /* DW_CFA_offset, x25, -32 */
2654 0x80 + 24, 5, /* DW_CFA_offset, x24, -40 */
2655 0x80 + 23, 6, /* DW_CFA_offset, x23, -48 */
2656 0x80 + 22, 7, /* DW_CFA_offset, x22, -56 */
2657 0x80 + 21, 8, /* DW_CFA_offset, x21, -64 */
2658 0x80 + 20, 9, /* DW_CFA_offset, x20, -72 */
2659 0x80 + 19, 10, /* DW_CFA_offset, x1p, -80 */
2660 0x80 + 30, 11, /* DW_CFA_offset, lr, -88 */
2661 0x80 + 29, 12, /* DW_CFA_offset, fp, -96 */
2662 }
2663};
2664
2665void tcg_register_jit(void *buf, size_t buf_size)
2666{
Richard Henderson38d195a2014-03-14 21:33:29 -04002667 tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
2668}