]> git.proxmox.com Git - mirror_qemu.git/blob - tcg/aarch64/tcg-target.c
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
[mirror_qemu.git] / tcg / aarch64 / tcg-target.c
1 /*
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
13 #include "tcg-be-ldst.h"
14 #include "qemu/bitops.h"
15
16 /* 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. */
19 QEMU_BUILD_BUG_ON(TCG_TYPE_I32 != 0 || TCG_TYPE_I64 != 1);
20
21 #ifndef NDEBUG
22 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
23 "%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",
27 "%fp", /* frame pointer */
28 "%lr", /* link register */
29 "%sp", /* stack pointer */
30 };
31 #endif /* NDEBUG */
32
33 #ifdef TARGET_WORDS_BIGENDIAN
34 #define TCG_LDST_BSWAP 1
35 #else
36 #define TCG_LDST_BSWAP 0
37 #endif
38
39 static const int tcg_target_reg_alloc_order[] = {
40 TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23,
41 TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27,
42 TCG_REG_X28, /* we will reserve this for GUEST_BASE if configured */
43
44 TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, TCG_REG_X12,
45 TCG_REG_X13, TCG_REG_X14, TCG_REG_X15,
46 TCG_REG_X16, TCG_REG_X17,
47
48 TCG_REG_X18, TCG_REG_X19, /* will not use these, see tcg_target_init */
49
50 TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
51 TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7,
52
53 TCG_REG_X8, /* will not use, see tcg_target_init */
54 };
55
56 static const int tcg_target_call_iarg_regs[8] = {
57 TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
58 TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7
59 };
60 static const int tcg_target_call_oarg_regs[1] = {
61 TCG_REG_X0
62 };
63
64 #define TCG_REG_TMP TCG_REG_X8
65
66 #ifndef CONFIG_SOFTMMU
67 # if defined(CONFIG_USE_GUEST_BASE)
68 # define TCG_REG_GUEST_BASE TCG_REG_X28
69 # else
70 # define TCG_REG_GUEST_BASE TCG_REG_XZR
71 # endif
72 #endif
73
74 static inline void reloc_pc26(void *code_ptr, intptr_t target)
75 {
76 intptr_t offset = (target - (intptr_t)code_ptr) / 4;
77 /* read instruction, mask away previous PC_REL26 parameter contents,
78 set the proper offset, then write back the instruction. */
79 uint32_t insn = *(uint32_t *)code_ptr;
80 insn = deposit32(insn, 0, 26, offset);
81 *(uint32_t *)code_ptr = insn;
82 }
83
84 static inline void reloc_pc19(void *code_ptr, intptr_t target)
85 {
86 intptr_t offset = (target - (intptr_t)code_ptr) / 4;
87 /* read instruction, mask away previous PC_REL19 parameter contents,
88 set the proper offset, then write back the instruction. */
89 uint32_t insn = *(uint32_t *)code_ptr;
90 insn = deposit32(insn, 5, 19, offset);
91 *(uint32_t *)code_ptr = insn;
92 }
93
94 static inline void patch_reloc(uint8_t *code_ptr, int type,
95 intptr_t value, intptr_t addend)
96 {
97 value += addend;
98
99 switch (type) {
100 case R_AARCH64_JUMP26:
101 case R_AARCH64_CALL26:
102 reloc_pc26(code_ptr, value);
103 break;
104 case R_AARCH64_CONDBR19:
105 reloc_pc19(code_ptr, value);
106 break;
107
108 default:
109 tcg_abort();
110 }
111 }
112
113 /* parse target specific constraints */
114 static int target_parse_constraint(TCGArgConstraint *ct,
115 const char **pct_str)
116 {
117 const char *ct_str = *pct_str;
118
119 switch (ct_str[0]) {
120 case 'r':
121 ct->ct |= TCG_CT_REG;
122 tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1);
123 break;
124 case 'l': /* qemu_ld / qemu_st address, data_reg */
125 ct->ct |= TCG_CT_REG;
126 tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1);
127 #ifdef CONFIG_SOFTMMU
128 /* x0 and x1 will be overwritten when reading the tlb entry,
129 and x2, and x3 for helper args, better to avoid using them. */
130 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X0);
131 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X1);
132 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X2);
133 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3);
134 #endif
135 break;
136 default:
137 return -1;
138 }
139
140 ct_str++;
141 *pct_str = ct_str;
142 return 0;
143 }
144
145 static inline int tcg_target_const_match(tcg_target_long val,
146 const TCGArgConstraint *arg_ct)
147 {
148 int ct = arg_ct->ct;
149
150 if (ct & TCG_CT_CONST) {
151 return 1;
152 }
153
154 return 0;
155 }
156
157 enum aarch64_cond_code {
158 COND_EQ = 0x0,
159 COND_NE = 0x1,
160 COND_CS = 0x2, /* Unsigned greater or equal */
161 COND_HS = COND_CS, /* ALIAS greater or equal */
162 COND_CC = 0x3, /* Unsigned less than */
163 COND_LO = COND_CC, /* ALIAS Lower */
164 COND_MI = 0x4, /* Negative */
165 COND_PL = 0x5, /* Zero or greater */
166 COND_VS = 0x6, /* Overflow */
167 COND_VC = 0x7, /* No overflow */
168 COND_HI = 0x8, /* Unsigned greater than */
169 COND_LS = 0x9, /* Unsigned less or equal */
170 COND_GE = 0xa,
171 COND_LT = 0xb,
172 COND_GT = 0xc,
173 COND_LE = 0xd,
174 COND_AL = 0xe,
175 COND_NV = 0xf, /* behaves like COND_AL here */
176 };
177
178 static const enum aarch64_cond_code tcg_cond_to_aarch64[] = {
179 [TCG_COND_EQ] = COND_EQ,
180 [TCG_COND_NE] = COND_NE,
181 [TCG_COND_LT] = COND_LT,
182 [TCG_COND_GE] = COND_GE,
183 [TCG_COND_LE] = COND_LE,
184 [TCG_COND_GT] = COND_GT,
185 /* unsigned */
186 [TCG_COND_LTU] = COND_LO,
187 [TCG_COND_GTU] = COND_HI,
188 [TCG_COND_GEU] = COND_HS,
189 [TCG_COND_LEU] = COND_LS,
190 };
191
192 /* opcodes for LDR / STR instructions with base + simm9 addressing */
193 enum aarch64_ldst_op_data { /* size of the data moved */
194 LDST_8 = 0x38,
195 LDST_16 = 0x78,
196 LDST_32 = 0xb8,
197 LDST_64 = 0xf8,
198 };
199 enum aarch64_ldst_op_type { /* type of operation */
200 LDST_ST = 0x0, /* store */
201 LDST_LD = 0x4, /* load */
202 LDST_LD_S_X = 0x8, /* load and sign-extend into Xt */
203 LDST_LD_S_W = 0xc, /* load and sign-extend into Wt */
204 };
205
206 enum aarch64_arith_opc {
207 ARITH_AND = 0x0a,
208 ARITH_ADD = 0x0b,
209 ARITH_OR = 0x2a,
210 ARITH_ADDS = 0x2b,
211 ARITH_XOR = 0x4a,
212 ARITH_SUB = 0x4b,
213 ARITH_ANDS = 0x6a,
214 ARITH_SUBS = 0x6b,
215 };
216
217 enum aarch64_srr_opc {
218 SRR_SHL = 0x0,
219 SRR_SHR = 0x4,
220 SRR_SAR = 0x8,
221 SRR_ROR = 0xc
222 };
223
224 static inline enum aarch64_ldst_op_data
225 aarch64_ldst_get_data(TCGOpcode tcg_op)
226 {
227 switch (tcg_op) {
228 case INDEX_op_ld8u_i32:
229 case INDEX_op_ld8s_i32:
230 case INDEX_op_ld8u_i64:
231 case INDEX_op_ld8s_i64:
232 case INDEX_op_st8_i32:
233 case INDEX_op_st8_i64:
234 return LDST_8;
235
236 case INDEX_op_ld16u_i32:
237 case INDEX_op_ld16s_i32:
238 case INDEX_op_ld16u_i64:
239 case INDEX_op_ld16s_i64:
240 case INDEX_op_st16_i32:
241 case INDEX_op_st16_i64:
242 return LDST_16;
243
244 case INDEX_op_ld_i32:
245 case INDEX_op_st_i32:
246 case INDEX_op_ld32u_i64:
247 case INDEX_op_ld32s_i64:
248 case INDEX_op_st32_i64:
249 return LDST_32;
250
251 case INDEX_op_ld_i64:
252 case INDEX_op_st_i64:
253 return LDST_64;
254
255 default:
256 tcg_abort();
257 }
258 }
259
260 static inline enum aarch64_ldst_op_type
261 aarch64_ldst_get_type(TCGOpcode tcg_op)
262 {
263 switch (tcg_op) {
264 case INDEX_op_st8_i32:
265 case INDEX_op_st16_i32:
266 case INDEX_op_st8_i64:
267 case INDEX_op_st16_i64:
268 case INDEX_op_st_i32:
269 case INDEX_op_st32_i64:
270 case INDEX_op_st_i64:
271 return LDST_ST;
272
273 case INDEX_op_ld8u_i32:
274 case INDEX_op_ld16u_i32:
275 case INDEX_op_ld8u_i64:
276 case INDEX_op_ld16u_i64:
277 case INDEX_op_ld_i32:
278 case INDEX_op_ld32u_i64:
279 case INDEX_op_ld_i64:
280 return LDST_LD;
281
282 case INDEX_op_ld8s_i32:
283 case INDEX_op_ld16s_i32:
284 return LDST_LD_S_W;
285
286 case INDEX_op_ld8s_i64:
287 case INDEX_op_ld16s_i64:
288 case INDEX_op_ld32s_i64:
289 return LDST_LD_S_X;
290
291 default:
292 tcg_abort();
293 }
294 }
295
296 static inline uint32_t tcg_in32(TCGContext *s)
297 {
298 uint32_t v = *(uint32_t *)s->code_ptr;
299 return v;
300 }
301
302 static inline void tcg_out_ldst_9(TCGContext *s,
303 enum aarch64_ldst_op_data op_data,
304 enum aarch64_ldst_op_type op_type,
305 TCGReg rd, TCGReg rn, tcg_target_long offset)
306 {
307 /* use LDUR with BASE register with 9bit signed unscaled offset */
308 tcg_out32(s, op_data << 24 | op_type << 20
309 | (offset & 0x1ff) << 12 | rn << 5 | rd);
310 }
311
312 /* tcg_out_ldst_12 expects a scaled unsigned immediate offset */
313 static inline void tcg_out_ldst_12(TCGContext *s,
314 enum aarch64_ldst_op_data op_data,
315 enum aarch64_ldst_op_type op_type,
316 TCGReg rd, TCGReg rn,
317 tcg_target_ulong scaled_uimm)
318 {
319 tcg_out32(s, (op_data | 1) << 24
320 | op_type << 20 | scaled_uimm << 10 | rn << 5 | rd);
321 }
322
323 static inline void tcg_out_movr(TCGContext *s, TCGType ext,
324 TCGReg rd, TCGReg src)
325 {
326 /* register to register move using MOV (shifted register with no shift) */
327 /* using MOV 0x2a0003e0 | (shift).. */
328 unsigned int base = ext ? 0xaa0003e0 : 0x2a0003e0;
329 tcg_out32(s, base | src << 16 | rd);
330 }
331
332 static inline void tcg_out_movi_aux(TCGContext *s,
333 TCGReg rd, uint64_t value)
334 {
335 uint32_t half, base, shift, movk = 0;
336 /* construct halfwords of the immediate with MOVZ/MOVK with LSL */
337 /* using MOVZ 0x52800000 | extended reg.. */
338 base = (value > 0xffffffff) ? 0xd2800000 : 0x52800000;
339 /* count trailing zeros in 16 bit steps, mapping 64 to 0. Emit the
340 first MOVZ with the half-word immediate skipping the zeros, with a shift
341 (LSL) equal to this number. Then morph all next instructions into MOVKs.
342 Zero the processed half-word in the value, continue until empty.
343 We build the final result 16bits at a time with up to 4 instructions,
344 but do not emit instructions for 16bit zero holes. */
345 do {
346 shift = ctz64(value) & (63 & -16);
347 half = (value >> shift) & 0xffff;
348 tcg_out32(s, base | movk | shift << 17 | half << 5 | rd);
349 movk = 0x20000000; /* morph next MOVZs into MOVKs */
350 value &= ~(0xffffUL << shift);
351 } while (value);
352 }
353
354 static inline void tcg_out_movi(TCGContext *s, TCGType type,
355 TCGReg rd, tcg_target_long value)
356 {
357 if (type == TCG_TYPE_I64) {
358 tcg_out_movi_aux(s, rd, value);
359 } else {
360 tcg_out_movi_aux(s, rd, value & 0xffffffff);
361 }
362 }
363
364 static inline void tcg_out_ldst_r(TCGContext *s,
365 enum aarch64_ldst_op_data op_data,
366 enum aarch64_ldst_op_type op_type,
367 TCGReg rd, TCGReg base, TCGReg regoff)
368 {
369 /* load from memory to register using base + 64bit register offset */
370 /* using f.e. STR Wt, [Xn, Xm] 0xb8600800|(regoff << 16)|(base << 5)|rd */
371 /* the 0x6000 is for the "no extend field" */
372 tcg_out32(s, 0x00206800
373 | op_data << 24 | op_type << 20 | regoff << 16 | base << 5 | rd);
374 }
375
376 /* solve the whole ldst problem */
377 static inline void tcg_out_ldst(TCGContext *s, enum aarch64_ldst_op_data data,
378 enum aarch64_ldst_op_type type,
379 TCGReg rd, TCGReg rn, tcg_target_long offset)
380 {
381 if (offset >= -256 && offset < 256) {
382 tcg_out_ldst_9(s, data, type, rd, rn, offset);
383 return;
384 }
385
386 if (offset >= 256) {
387 /* if the offset is naturally aligned and in range,
388 then we can use the scaled uimm12 encoding */
389 unsigned int s_bits = data >> 6;
390 if (!(offset & ((1 << s_bits) - 1))) {
391 tcg_target_ulong scaled_uimm = offset >> s_bits;
392 if (scaled_uimm <= 0xfff) {
393 tcg_out_ldst_12(s, data, type, rd, rn, scaled_uimm);
394 return;
395 }
396 }
397 }
398
399 /* worst-case scenario, move offset to temp register, use reg offset */
400 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset);
401 tcg_out_ldst_r(s, data, type, rd, rn, TCG_REG_TMP);
402 }
403
404 /* mov alias implemented with add immediate, useful to move to/from SP */
405 static inline void tcg_out_movr_sp(TCGContext *s, TCGType ext,
406 TCGReg rd, TCGReg rn)
407 {
408 /* using ADD 0x11000000 | (ext) | rn << 5 | rd */
409 unsigned int base = ext ? 0x91000000 : 0x11000000;
410 tcg_out32(s, base | rn << 5 | rd);
411 }
412
413 static inline void tcg_out_mov(TCGContext *s,
414 TCGType type, TCGReg ret, TCGReg arg)
415 {
416 if (ret != arg) {
417 tcg_out_movr(s, type == TCG_TYPE_I64, ret, arg);
418 }
419 }
420
421 static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
422 TCGReg arg1, intptr_t arg2)
423 {
424 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_LD,
425 arg, arg1, arg2);
426 }
427
428 static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
429 TCGReg arg1, intptr_t arg2)
430 {
431 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_ST,
432 arg, arg1, arg2);
433 }
434
435 static inline void tcg_out_arith(TCGContext *s, enum aarch64_arith_opc opc,
436 TCGType ext, TCGReg rd, TCGReg rn, TCGReg rm,
437 int shift_imm)
438 {
439 /* Using shifted register arithmetic operations */
440 /* if extended register operation (64bit) just OR with 0x80 << 24 */
441 unsigned int shift, base = ext ? (0x80 | opc) << 24 : opc << 24;
442 if (shift_imm == 0) {
443 shift = 0;
444 } else if (shift_imm > 0) {
445 shift = shift_imm << 10 | 1 << 22;
446 } else /* (shift_imm < 0) */ {
447 shift = (-shift_imm) << 10;
448 }
449 tcg_out32(s, base | rm << 16 | shift | rn << 5 | rd);
450 }
451
452 static inline void tcg_out_mul(TCGContext *s, TCGType ext,
453 TCGReg rd, TCGReg rn, TCGReg rm)
454 {
455 /* Using MADD 0x1b000000 with Ra = wzr alias MUL 0x1b007c00 */
456 unsigned int base = ext ? 0x9b007c00 : 0x1b007c00;
457 tcg_out32(s, base | rm << 16 | rn << 5 | rd);
458 }
459
460 static inline void tcg_out_shiftrot_reg(TCGContext *s,
461 enum aarch64_srr_opc opc, TCGType ext,
462 TCGReg rd, TCGReg rn, TCGReg rm)
463 {
464 /* using 2-source data processing instructions 0x1ac02000 */
465 unsigned int base = ext ? 0x9ac02000 : 0x1ac02000;
466 tcg_out32(s, base | rm << 16 | opc << 8 | rn << 5 | rd);
467 }
468
469 static inline void tcg_out_ubfm(TCGContext *s, TCGType ext, TCGReg rd,
470 TCGReg rn, unsigned int a, unsigned int b)
471 {
472 /* Using UBFM 0x53000000 Wd, Wn, a, b */
473 unsigned int base = ext ? 0xd3400000 : 0x53000000;
474 tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd);
475 }
476
477 static inline void tcg_out_sbfm(TCGContext *s, TCGType ext, TCGReg rd,
478 TCGReg rn, unsigned int a, unsigned int b)
479 {
480 /* Using SBFM 0x13000000 Wd, Wn, a, b */
481 unsigned int base = ext ? 0x93400000 : 0x13000000;
482 tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd);
483 }
484
485 static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd,
486 TCGReg rn, TCGReg rm, unsigned int a)
487 {
488 /* Using EXTR 0x13800000 Wd, Wn, Wm, a */
489 unsigned int base = ext ? 0x93c00000 : 0x13800000;
490 tcg_out32(s, base | rm << 16 | a << 10 | rn << 5 | rd);
491 }
492
493 static inline void tcg_out_shl(TCGContext *s, TCGType ext,
494 TCGReg rd, TCGReg rn, unsigned int m)
495 {
496 int bits, max;
497 bits = ext ? 64 : 32;
498 max = bits - 1;
499 tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max));
500 }
501
502 static inline void tcg_out_shr(TCGContext *s, TCGType ext,
503 TCGReg rd, TCGReg rn, unsigned int m)
504 {
505 int max = ext ? 63 : 31;
506 tcg_out_ubfm(s, ext, rd, rn, m & max, max);
507 }
508
509 static inline void tcg_out_sar(TCGContext *s, TCGType ext,
510 TCGReg rd, TCGReg rn, unsigned int m)
511 {
512 int max = ext ? 63 : 31;
513 tcg_out_sbfm(s, ext, rd, rn, m & max, max);
514 }
515
516 static inline void tcg_out_rotr(TCGContext *s, TCGType ext,
517 TCGReg rd, TCGReg rn, unsigned int m)
518 {
519 int max = ext ? 63 : 31;
520 tcg_out_extr(s, ext, rd, rn, rn, m & max);
521 }
522
523 static inline void tcg_out_rotl(TCGContext *s, TCGType ext,
524 TCGReg rd, TCGReg rn, unsigned int m)
525 {
526 int bits, max;
527 bits = ext ? 64 : 32;
528 max = bits - 1;
529 tcg_out_extr(s, ext, rd, rn, rn, bits - (m & max));
530 }
531
532 static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGReg rn, TCGReg rm)
533 {
534 /* Using CMP alias SUBS wzr, Wn, Wm */
535 tcg_out_arith(s, ARITH_SUBS, ext, TCG_REG_XZR, rn, rm, 0);
536 }
537
538 static inline void tcg_out_cset(TCGContext *s, TCGType ext,
539 TCGReg rd, TCGCond c)
540 {
541 /* Using CSET alias of CSINC 0x1a800400 Xd, XZR, XZR, invert(cond) */
542 unsigned int base = ext ? 0x9a9f07e0 : 0x1a9f07e0;
543 tcg_out32(s, base | tcg_cond_to_aarch64[tcg_invert_cond(c)] << 12 | rd);
544 }
545
546 static inline void tcg_out_goto(TCGContext *s, intptr_t target)
547 {
548 intptr_t offset = (target - (intptr_t)s->code_ptr) / 4;
549
550 if (offset < -0x02000000 || offset >= 0x02000000) {
551 /* out of 26bit range */
552 tcg_abort();
553 }
554
555 tcg_out32(s, 0x14000000 | (offset & 0x03ffffff));
556 }
557
558 static inline void tcg_out_goto_noaddr(TCGContext *s)
559 {
560 /* We pay attention here to not modify the branch target by
561 reading from the buffer. This ensure that caches and memory are
562 kept coherent during retranslation.
563 Mask away possible garbage in the high bits for the first translation,
564 while keeping the offset bits for retranslation. */
565 uint32_t insn;
566 insn = (tcg_in32(s) & 0x03ffffff) | 0x14000000;
567 tcg_out32(s, insn);
568 }
569
570 static inline void tcg_out_goto_cond_noaddr(TCGContext *s, TCGCond c)
571 {
572 /* see comments in tcg_out_goto_noaddr */
573 uint32_t insn;
574 insn = tcg_in32(s) & (0x07ffff << 5);
575 insn |= 0x54000000 | tcg_cond_to_aarch64[c];
576 tcg_out32(s, insn);
577 }
578
579 static inline void tcg_out_goto_cond(TCGContext *s, TCGCond c, intptr_t target)
580 {
581 intptr_t offset = (target - (intptr_t)s->code_ptr) / 4;
582
583 if (offset < -0x40000 || offset >= 0x40000) {
584 /* out of 19bit range */
585 tcg_abort();
586 }
587
588 offset &= 0x7ffff;
589 tcg_out32(s, 0x54000000 | tcg_cond_to_aarch64[c] | offset << 5);
590 }
591
592 static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
593 {
594 tcg_out32(s, 0xd63f0000 | reg << 5);
595 }
596
597 static inline void tcg_out_gotor(TCGContext *s, TCGReg reg)
598 {
599 tcg_out32(s, 0xd61f0000 | reg << 5);
600 }
601
602 static inline void tcg_out_call(TCGContext *s, intptr_t target)
603 {
604 intptr_t offset = (target - (intptr_t)s->code_ptr) / 4;
605
606 if (offset < -0x02000000 || offset >= 0x02000000) { /* out of 26bit rng */
607 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, target);
608 tcg_out_callr(s, TCG_REG_TMP);
609 } else {
610 tcg_out32(s, 0x94000000 | (offset & 0x03ffffff));
611 }
612 }
613
614 /* encode a logical immediate, mapping user parameter
615 M=set bits pattern length to S=M-1 */
616 static inline unsigned int
617 aarch64_limm(unsigned int m, unsigned int r)
618 {
619 assert(m > 0);
620 return r << 16 | (m - 1) << 10;
621 }
622
623 /* test a register against an immediate bit pattern made of
624 M set bits rotated right by R.
625 Examples:
626 to test a 32/64 reg against 0x00000007, pass M = 3, R = 0.
627 to test a 32/64 reg against 0x000000ff, pass M = 8, R = 0.
628 to test a 32bit reg against 0xff000000, pass M = 8, R = 8.
629 to test a 32bit reg against 0xff0000ff, pass M = 16, R = 8.
630 */
631 static inline void tcg_out_tst(TCGContext *s, TCGType ext, TCGReg rn,
632 unsigned int m, unsigned int r)
633 {
634 /* using TST alias of ANDS XZR, Xn,#bimm64 0x7200001f */
635 unsigned int base = ext ? 0xf240001f : 0x7200001f;
636 tcg_out32(s, base | aarch64_limm(m, r) | rn << 5);
637 }
638
639 /* and a register with a bit pattern, similarly to TST, no flags change */
640 static inline void tcg_out_andi(TCGContext *s, TCGType ext, TCGReg rd,
641 TCGReg rn, unsigned int m, unsigned int r)
642 {
643 /* using AND 0x12000000 */
644 unsigned int base = ext ? 0x92400000 : 0x12000000;
645 tcg_out32(s, base | aarch64_limm(m, r) | rn << 5 | rd);
646 }
647
648 static inline void tcg_out_ret(TCGContext *s)
649 {
650 /* emit RET { LR } */
651 tcg_out32(s, 0xd65f03c0);
652 }
653
654 void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr)
655 {
656 intptr_t target = addr;
657 intptr_t offset = (target - (intptr_t)jmp_addr) / 4;
658
659 if (offset < -0x02000000 || offset >= 0x02000000) {
660 /* out of 26bit range */
661 tcg_abort();
662 }
663
664 patch_reloc((uint8_t *)jmp_addr, R_AARCH64_JUMP26, target, 0);
665 flush_icache_range(jmp_addr, jmp_addr + 4);
666 }
667
668 static inline void tcg_out_goto_label(TCGContext *s, int label_index)
669 {
670 TCGLabel *l = &s->labels[label_index];
671
672 if (!l->has_value) {
673 tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, label_index, 0);
674 tcg_out_goto_noaddr(s);
675 } else {
676 tcg_out_goto(s, l->u.value);
677 }
678 }
679
680 static inline void tcg_out_goto_label_cond(TCGContext *s,
681 TCGCond c, int label_index)
682 {
683 TCGLabel *l = &s->labels[label_index];
684
685 if (!l->has_value) {
686 tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, label_index, 0);
687 tcg_out_goto_cond_noaddr(s, c);
688 } else {
689 tcg_out_goto_cond(s, c, l->u.value);
690 }
691 }
692
693 static inline void tcg_out_rev(TCGContext *s, TCGType ext,
694 TCGReg rd, TCGReg rm)
695 {
696 /* using REV 0x5ac00800 */
697 unsigned int base = ext ? 0xdac00c00 : 0x5ac00800;
698 tcg_out32(s, base | rm << 5 | rd);
699 }
700
701 static inline void tcg_out_rev16(TCGContext *s, TCGType ext,
702 TCGReg rd, TCGReg rm)
703 {
704 /* using REV16 0x5ac00400 */
705 unsigned int base = ext ? 0xdac00400 : 0x5ac00400;
706 tcg_out32(s, base | rm << 5 | rd);
707 }
708
709 static inline void tcg_out_sxt(TCGContext *s, TCGType ext, int s_bits,
710 TCGReg rd, TCGReg rn)
711 {
712 /* using ALIASes SXTB 0x13001c00, SXTH 0x13003c00, SXTW 0x93407c00
713 of SBFM Xd, Xn, #0, #7|15|31 */
714 int bits = 8 * (1 << s_bits) - 1;
715 tcg_out_sbfm(s, ext, rd, rn, 0, bits);
716 }
717
718 static inline void tcg_out_uxt(TCGContext *s, int s_bits,
719 TCGReg rd, TCGReg rn)
720 {
721 /* using ALIASes UXTB 0x53001c00, UXTH 0x53003c00
722 of UBFM Wd, Wn, #0, #7|15 */
723 int bits = 8 * (1 << s_bits) - 1;
724 tcg_out_ubfm(s, 0, rd, rn, 0, bits);
725 }
726
727 static inline void tcg_out_addi(TCGContext *s, TCGType ext,
728 TCGReg rd, TCGReg rn, unsigned int aimm)
729 {
730 /* add immediate aimm unsigned 12bit value (with LSL 0 or 12) */
731 /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
732 unsigned int base = ext ? 0x91000000 : 0x11000000;
733
734 if (aimm <= 0xfff) {
735 aimm <<= 10;
736 } else {
737 /* we can only shift left by 12, on assert we cannot represent */
738 assert(!(aimm & 0xfff));
739 assert(aimm <= 0xfff000);
740 base |= 1 << 22; /* apply LSL 12 */
741 aimm >>= 2;
742 }
743
744 tcg_out32(s, base | aimm | (rn << 5) | rd);
745 }
746
747 static inline void tcg_out_subi(TCGContext *s, TCGType ext,
748 TCGReg rd, TCGReg rn, unsigned int aimm)
749 {
750 /* sub immediate aimm unsigned 12bit value (with LSL 0 or 12) */
751 /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
752 unsigned int base = ext ? 0xd1000000 : 0x51000000;
753
754 if (aimm <= 0xfff) {
755 aimm <<= 10;
756 } else {
757 /* we can only shift left by 12, on assert we cannot represent */
758 assert(!(aimm & 0xfff));
759 assert(aimm <= 0xfff000);
760 base |= 1 << 22; /* apply LSL 12 */
761 aimm >>= 2;
762 }
763
764 tcg_out32(s, base | aimm | (rn << 5) | rd);
765 }
766
767 #ifdef CONFIG_SOFTMMU
768 /* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
769 * int mmu_idx, uintptr_t ra)
770 */
771 static const void * const qemu_ld_helpers[4] = {
772 helper_ret_ldub_mmu,
773 helper_ret_lduw_mmu,
774 helper_ret_ldul_mmu,
775 helper_ret_ldq_mmu,
776 };
777
778 /* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
779 * uintxx_t val, int mmu_idx, uintptr_t ra)
780 */
781 static const void * const qemu_st_helpers[4] = {
782 helper_ret_stb_mmu,
783 helper_ret_stw_mmu,
784 helper_ret_stl_mmu,
785 helper_ret_stq_mmu,
786 };
787
788 static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
789 {
790 reloc_pc19(lb->label_ptr[0], (intptr_t)s->code_ptr);
791
792 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
793 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, lb->addrlo_reg);
794 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, lb->mem_index);
795 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_X3, (tcg_target_long)lb->raddr);
796 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
797 (tcg_target_long)qemu_ld_helpers[lb->opc & 3]);
798 tcg_out_callr(s, TCG_REG_TMP);
799 if (lb->opc & 0x04) {
800 tcg_out_sxt(s, 1, lb->opc & 3, lb->datalo_reg, TCG_REG_X0);
801 } else {
802 tcg_out_movr(s, 1, lb->datalo_reg, TCG_REG_X0);
803 }
804
805 tcg_out_goto(s, (intptr_t)lb->raddr);
806 }
807
808 static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
809 {
810 reloc_pc19(lb->label_ptr[0], (intptr_t)s->code_ptr);
811
812 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
813 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, lb->addrlo_reg);
814 tcg_out_movr(s, 1, TCG_REG_X2, lb->datalo_reg);
815 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, lb->mem_index);
816 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_X4, (intptr_t)lb->raddr);
817 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
818 (intptr_t)qemu_st_helpers[lb->opc & 3]);
819 tcg_out_callr(s, TCG_REG_TMP);
820 tcg_out_goto(s, (tcg_target_long)lb->raddr);
821 }
822
823 static void add_qemu_ldst_label(TCGContext *s, int is_ld, int opc,
824 TCGReg data_reg, TCGReg addr_reg,
825 int mem_index,
826 uint8_t *raddr, uint8_t *label_ptr)
827 {
828 TCGLabelQemuLdst *label = new_ldst_label(s);
829
830 label->is_ld = is_ld;
831 label->opc = opc;
832 label->datalo_reg = data_reg;
833 label->addrlo_reg = addr_reg;
834 label->mem_index = mem_index;
835 label->raddr = raddr;
836 label->label_ptr[0] = label_ptr;
837 }
838
839 /* Load and compare a TLB entry, emitting the conditional jump to the
840 slow path for the failure case, which will be patched later when finalizing
841 the slow path. Generated code returns the host addend in X1,
842 clobbers X0,X2,X3,TMP. */
843 static void tcg_out_tlb_read(TCGContext *s, TCGReg addr_reg,
844 int s_bits, uint8_t **label_ptr, int mem_index, int is_read)
845 {
846 TCGReg base = TCG_AREG0;
847 int tlb_offset = is_read ?
848 offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
849 : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write);
850 /* Extract the TLB index from the address into X0.
851 X0<CPU_TLB_BITS:0> =
852 addr_reg<TARGET_PAGE_BITS+CPU_TLB_BITS:TARGET_PAGE_BITS> */
853 tcg_out_ubfm(s, (TARGET_LONG_BITS == 64), TCG_REG_X0, addr_reg,
854 TARGET_PAGE_BITS, TARGET_PAGE_BITS + CPU_TLB_BITS);
855 /* Store the page mask part of the address and the low s_bits into X3.
856 Later this allows checking for equality and alignment at the same time.
857 X3 = addr_reg & (PAGE_MASK | ((1 << s_bits) - 1)) */
858 tcg_out_andi(s, (TARGET_LONG_BITS == 64), TCG_REG_X3, addr_reg,
859 (TARGET_LONG_BITS - TARGET_PAGE_BITS) + s_bits,
860 (TARGET_LONG_BITS - TARGET_PAGE_BITS));
861 /* Add any "high bits" from the tlb offset to the env address into X2,
862 to take advantage of the LSL12 form of the addi instruction.
863 X2 = env + (tlb_offset & 0xfff000) */
864 tcg_out_addi(s, 1, TCG_REG_X2, base, tlb_offset & 0xfff000);
865 /* Merge the tlb index contribution into X2.
866 X2 = X2 + (X0 << CPU_TLB_ENTRY_BITS) */
867 tcg_out_arith(s, ARITH_ADD, 1, TCG_REG_X2, TCG_REG_X2,
868 TCG_REG_X0, -CPU_TLB_ENTRY_BITS);
869 /* Merge "low bits" from tlb offset, load the tlb comparator into X0.
870 X0 = load [X2 + (tlb_offset & 0x000fff)] */
871 tcg_out_ldst(s, TARGET_LONG_BITS == 64 ? LDST_64 : LDST_32,
872 LDST_LD, TCG_REG_X0, TCG_REG_X2,
873 (tlb_offset & 0xfff));
874 /* Load the tlb addend. Do that early to avoid stalling.
875 X1 = load [X2 + (tlb_offset & 0xfff) + offsetof(addend)] */
876 tcg_out_ldst(s, LDST_64, LDST_LD, TCG_REG_X1, TCG_REG_X2,
877 (tlb_offset & 0xfff) + (offsetof(CPUTLBEntry, addend)) -
878 (is_read ? offsetof(CPUTLBEntry, addr_read)
879 : offsetof(CPUTLBEntry, addr_write)));
880 /* Perform the address comparison. */
881 tcg_out_cmp(s, (TARGET_LONG_BITS == 64), TCG_REG_X0, TCG_REG_X3);
882 *label_ptr = s->code_ptr;
883 /* If not equal, we jump to the slow path. */
884 tcg_out_goto_cond_noaddr(s, TCG_COND_NE);
885 }
886
887 #endif /* CONFIG_SOFTMMU */
888
889 static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data_r,
890 TCGReg addr_r, TCGReg off_r)
891 {
892 switch (opc) {
893 case 0:
894 tcg_out_ldst_r(s, LDST_8, LDST_LD, data_r, addr_r, off_r);
895 break;
896 case 0 | 4:
897 tcg_out_ldst_r(s, LDST_8, LDST_LD_S_X, data_r, addr_r, off_r);
898 break;
899 case 1:
900 tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r);
901 if (TCG_LDST_BSWAP) {
902 tcg_out_rev16(s, 0, data_r, data_r);
903 }
904 break;
905 case 1 | 4:
906 if (TCG_LDST_BSWAP) {
907 tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r);
908 tcg_out_rev16(s, 0, data_r, data_r);
909 tcg_out_sxt(s, 1, 1, data_r, data_r);
910 } else {
911 tcg_out_ldst_r(s, LDST_16, LDST_LD_S_X, data_r, addr_r, off_r);
912 }
913 break;
914 case 2:
915 tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r);
916 if (TCG_LDST_BSWAP) {
917 tcg_out_rev(s, 0, data_r, data_r);
918 }
919 break;
920 case 2 | 4:
921 if (TCG_LDST_BSWAP) {
922 tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r);
923 tcg_out_rev(s, 0, data_r, data_r);
924 tcg_out_sxt(s, 1, 2, data_r, data_r);
925 } else {
926 tcg_out_ldst_r(s, LDST_32, LDST_LD_S_X, data_r, addr_r, off_r);
927 }
928 break;
929 case 3:
930 tcg_out_ldst_r(s, LDST_64, LDST_LD, data_r, addr_r, off_r);
931 if (TCG_LDST_BSWAP) {
932 tcg_out_rev(s, 1, data_r, data_r);
933 }
934 break;
935 default:
936 tcg_abort();
937 }
938 }
939
940 static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data_r,
941 TCGReg addr_r, TCGReg off_r)
942 {
943 switch (opc) {
944 case 0:
945 tcg_out_ldst_r(s, LDST_8, LDST_ST, data_r, addr_r, off_r);
946 break;
947 case 1:
948 if (TCG_LDST_BSWAP) {
949 tcg_out_rev16(s, 0, TCG_REG_TMP, data_r);
950 tcg_out_ldst_r(s, LDST_16, LDST_ST, TCG_REG_TMP, addr_r, off_r);
951 } else {
952 tcg_out_ldst_r(s, LDST_16, LDST_ST, data_r, addr_r, off_r);
953 }
954 break;
955 case 2:
956 if (TCG_LDST_BSWAP) {
957 tcg_out_rev(s, 0, TCG_REG_TMP, data_r);
958 tcg_out_ldst_r(s, LDST_32, LDST_ST, TCG_REG_TMP, addr_r, off_r);
959 } else {
960 tcg_out_ldst_r(s, LDST_32, LDST_ST, data_r, addr_r, off_r);
961 }
962 break;
963 case 3:
964 if (TCG_LDST_BSWAP) {
965 tcg_out_rev(s, 1, TCG_REG_TMP, data_r);
966 tcg_out_ldst_r(s, LDST_64, LDST_ST, TCG_REG_TMP, addr_r, off_r);
967 } else {
968 tcg_out_ldst_r(s, LDST_64, LDST_ST, data_r, addr_r, off_r);
969 }
970 break;
971 default:
972 tcg_abort();
973 }
974 }
975
976 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
977 {
978 TCGReg addr_reg, data_reg;
979 #ifdef CONFIG_SOFTMMU
980 int mem_index, s_bits;
981 uint8_t *label_ptr;
982 #endif
983 data_reg = args[0];
984 addr_reg = args[1];
985
986 #ifdef CONFIG_SOFTMMU
987 mem_index = args[2];
988 s_bits = opc & 3;
989 tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 1);
990 tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, TCG_REG_X1);
991 add_qemu_ldst_label(s, 1, opc, data_reg, addr_reg,
992 mem_index, s->code_ptr, label_ptr);
993 #else /* !CONFIG_SOFTMMU */
994 tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg,
995 GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
996 #endif /* CONFIG_SOFTMMU */
997 }
998
999 static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
1000 {
1001 TCGReg addr_reg, data_reg;
1002 #ifdef CONFIG_SOFTMMU
1003 int mem_index, s_bits;
1004 uint8_t *label_ptr;
1005 #endif
1006 data_reg = args[0];
1007 addr_reg = args[1];
1008
1009 #ifdef CONFIG_SOFTMMU
1010 mem_index = args[2];
1011 s_bits = opc & 3;
1012
1013 tcg_out_tlb_read(s, addr_reg, s_bits, &label_ptr, mem_index, 0);
1014 tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, TCG_REG_X1);
1015 add_qemu_ldst_label(s, 0, opc, data_reg, addr_reg,
1016 mem_index, s->code_ptr, label_ptr);
1017 #else /* !CONFIG_SOFTMMU */
1018 tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg,
1019 GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
1020 #endif /* CONFIG_SOFTMMU */
1021 }
1022
1023 static uint8_t *tb_ret_addr;
1024
1025 /* callee stack use example:
1026 stp x29, x30, [sp,#-32]!
1027 mov x29, sp
1028 stp x1, x2, [sp,#16]
1029 ...
1030 ldp x1, x2, [sp,#16]
1031 ldp x29, x30, [sp],#32
1032 ret
1033 */
1034
1035 /* push r1 and r2, and alloc stack space for a total of
1036 alloc_n elements (1 element=16 bytes, must be between 1 and 31. */
1037 static inline void tcg_out_push_pair(TCGContext *s, TCGReg addr,
1038 TCGReg r1, TCGReg r2, int alloc_n)
1039 {
1040 /* using indexed scaled simm7 STP 0x28800000 | (ext) | 0x01000000 (pre-idx)
1041 | alloc_n * (-1) << 16 | r2 << 10 | addr << 5 | r1 */
1042 assert(alloc_n > 0 && alloc_n < 0x20);
1043 alloc_n = (-alloc_n) & 0x3f;
1044 tcg_out32(s, 0xa9800000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
1045 }
1046
1047 /* dealloc stack space for a total of alloc_n elements and pop r1, r2. */
1048 static inline void tcg_out_pop_pair(TCGContext *s, TCGReg addr,
1049 TCGReg r1, TCGReg r2, int alloc_n)
1050 {
1051 /* using indexed scaled simm7 LDP 0x28c00000 | (ext) | nothing (post-idx)
1052 | alloc_n << 16 | r2 << 10 | addr << 5 | r1 */
1053 assert(alloc_n > 0 && alloc_n < 0x20);
1054 tcg_out32(s, 0xa8c00000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
1055 }
1056
1057 static inline void tcg_out_store_pair(TCGContext *s, TCGReg addr,
1058 TCGReg r1, TCGReg r2, int idx)
1059 {
1060 /* using register pair offset simm7 STP 0x29000000 | (ext)
1061 | idx << 16 | r2 << 10 | addr << 5 | r1 */
1062 assert(idx > 0 && idx < 0x20);
1063 tcg_out32(s, 0xa9000000 | idx << 16 | r2 << 10 | addr << 5 | r1);
1064 }
1065
1066 static inline void tcg_out_load_pair(TCGContext *s, TCGReg addr,
1067 TCGReg r1, TCGReg r2, int idx)
1068 {
1069 /* using register pair offset simm7 LDP 0x29400000 | (ext)
1070 | idx << 16 | r2 << 10 | addr << 5 | r1 */
1071 assert(idx > 0 && idx < 0x20);
1072 tcg_out32(s, 0xa9400000 | idx << 16 | r2 << 10 | addr << 5 | r1);
1073 }
1074
1075 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
1076 const TCGArg args[TCG_MAX_OP_ARGS],
1077 const int const_args[TCG_MAX_OP_ARGS])
1078 {
1079 /* 99% of the time, we can signal the use of extension registers
1080 by looking to see if the opcode handles 64-bit data. */
1081 TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0;
1082
1083 /* Hoist the loads of the most common arguments. */
1084 TCGArg a0 = args[0];
1085 TCGArg a1 = args[1];
1086 TCGArg a2 = args[2];
1087 int c2 = const_args[2];
1088
1089 switch (opc) {
1090 case INDEX_op_exit_tb:
1091 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, a0);
1092 tcg_out_goto(s, (intptr_t)tb_ret_addr);
1093 break;
1094
1095 case INDEX_op_goto_tb:
1096 #ifndef USE_DIRECT_JUMP
1097 #error "USE_DIRECT_JUMP required for aarch64"
1098 #endif
1099 assert(s->tb_jmp_offset != NULL); /* consistency for USE_DIRECT_JUMP */
1100 s->tb_jmp_offset[a0] = s->code_ptr - s->code_buf;
1101 /* actual branch destination will be patched by
1102 aarch64_tb_set_jmp_target later, beware retranslation. */
1103 tcg_out_goto_noaddr(s);
1104 s->tb_next_offset[a0] = s->code_ptr - s->code_buf;
1105 break;
1106
1107 case INDEX_op_call:
1108 if (const_args[0]) {
1109 tcg_out_call(s, a0);
1110 } else {
1111 tcg_out_callr(s, a0);
1112 }
1113 break;
1114
1115 case INDEX_op_br:
1116 tcg_out_goto_label(s, a0);
1117 break;
1118
1119 case INDEX_op_ld_i32:
1120 case INDEX_op_ld_i64:
1121 case INDEX_op_st_i32:
1122 case INDEX_op_st_i64:
1123 case INDEX_op_ld8u_i32:
1124 case INDEX_op_ld8s_i32:
1125 case INDEX_op_ld16u_i32:
1126 case INDEX_op_ld16s_i32:
1127 case INDEX_op_ld8u_i64:
1128 case INDEX_op_ld8s_i64:
1129 case INDEX_op_ld16u_i64:
1130 case INDEX_op_ld16s_i64:
1131 case INDEX_op_ld32u_i64:
1132 case INDEX_op_ld32s_i64:
1133 case INDEX_op_st8_i32:
1134 case INDEX_op_st8_i64:
1135 case INDEX_op_st16_i32:
1136 case INDEX_op_st16_i64:
1137 case INDEX_op_st32_i64:
1138 tcg_out_ldst(s, aarch64_ldst_get_data(opc), aarch64_ldst_get_type(opc),
1139 a0, a1, a2);
1140 break;
1141
1142 case INDEX_op_add_i64:
1143 case INDEX_op_add_i32:
1144 tcg_out_arith(s, ARITH_ADD, ext, a0, a1, a2, 0);
1145 break;
1146
1147 case INDEX_op_sub_i64:
1148 case INDEX_op_sub_i32:
1149 tcg_out_arith(s, ARITH_SUB, ext, a0, a1, a2, 0);
1150 break;
1151
1152 case INDEX_op_and_i64:
1153 case INDEX_op_and_i32:
1154 tcg_out_arith(s, ARITH_AND, ext, a0, a1, a2, 0);
1155 break;
1156
1157 case INDEX_op_or_i64:
1158 case INDEX_op_or_i32:
1159 tcg_out_arith(s, ARITH_OR, ext, a0, a1, a2, 0);
1160 break;
1161
1162 case INDEX_op_xor_i64:
1163 case INDEX_op_xor_i32:
1164 tcg_out_arith(s, ARITH_XOR, ext, a0, a1, a2, 0);
1165 break;
1166
1167 case INDEX_op_mul_i64:
1168 case INDEX_op_mul_i32:
1169 tcg_out_mul(s, ext, a0, a1, a2);
1170 break;
1171
1172 case INDEX_op_shl_i64:
1173 case INDEX_op_shl_i32:
1174 if (c2) { /* LSL / UBFM Wd, Wn, (32 - m) */
1175 tcg_out_shl(s, ext, a0, a1, a2);
1176 } else { /* LSL / LSLV */
1177 tcg_out_shiftrot_reg(s, SRR_SHL, ext, a0, a1, a2);
1178 }
1179 break;
1180
1181 case INDEX_op_shr_i64:
1182 case INDEX_op_shr_i32:
1183 if (c2) { /* LSR / UBFM Wd, Wn, m, 31 */
1184 tcg_out_shr(s, ext, a0, a1, a2);
1185 } else { /* LSR / LSRV */
1186 tcg_out_shiftrot_reg(s, SRR_SHR, ext, a0, a1, a2);
1187 }
1188 break;
1189
1190 case INDEX_op_sar_i64:
1191 case INDEX_op_sar_i32:
1192 if (c2) { /* ASR / SBFM Wd, Wn, m, 31 */
1193 tcg_out_sar(s, ext, a0, a1, a2);
1194 } else { /* ASR / ASRV */
1195 tcg_out_shiftrot_reg(s, SRR_SAR, ext, a0, a1, a2);
1196 }
1197 break;
1198
1199 case INDEX_op_rotr_i64:
1200 case INDEX_op_rotr_i32:
1201 if (c2) { /* ROR / EXTR Wd, Wm, Wm, m */
1202 tcg_out_rotr(s, ext, a0, a1, a2);
1203 } else { /* ROR / RORV */
1204 tcg_out_shiftrot_reg(s, SRR_ROR, ext, a0, a1, a2);
1205 }
1206 break;
1207
1208 case INDEX_op_rotl_i64:
1209 case INDEX_op_rotl_i32: /* same as rotate right by (32 - m) */
1210 if (c2) { /* ROR / EXTR Wd, Wm, Wm, 32 - m */
1211 tcg_out_rotl(s, ext, a0, a1, a2);
1212 } else {
1213 tcg_out_arith(s, ARITH_SUB, 0, TCG_REG_TMP, TCG_REG_XZR, a2, 0);
1214 tcg_out_shiftrot_reg(s, SRR_ROR, ext, a0, a1, TCG_REG_TMP);
1215 }
1216 break;
1217
1218 case INDEX_op_brcond_i64:
1219 case INDEX_op_brcond_i32:
1220 tcg_out_cmp(s, ext, a0, a1);
1221 tcg_out_goto_label_cond(s, a2, args[3]);
1222 break;
1223
1224 case INDEX_op_setcond_i64:
1225 case INDEX_op_setcond_i32:
1226 tcg_out_cmp(s, ext, a1, a2);
1227 tcg_out_cset(s, 0, a0, args[3]);
1228 break;
1229
1230 case INDEX_op_qemu_ld8u:
1231 tcg_out_qemu_ld(s, args, 0 | 0);
1232 break;
1233 case INDEX_op_qemu_ld8s:
1234 tcg_out_qemu_ld(s, args, 4 | 0);
1235 break;
1236 case INDEX_op_qemu_ld16u:
1237 tcg_out_qemu_ld(s, args, 0 | 1);
1238 break;
1239 case INDEX_op_qemu_ld16s:
1240 tcg_out_qemu_ld(s, args, 4 | 1);
1241 break;
1242 case INDEX_op_qemu_ld32u:
1243 tcg_out_qemu_ld(s, args, 0 | 2);
1244 break;
1245 case INDEX_op_qemu_ld32s:
1246 tcg_out_qemu_ld(s, args, 4 | 2);
1247 break;
1248 case INDEX_op_qemu_ld32:
1249 tcg_out_qemu_ld(s, args, 0 | 2);
1250 break;
1251 case INDEX_op_qemu_ld64:
1252 tcg_out_qemu_ld(s, args, 0 | 3);
1253 break;
1254 case INDEX_op_qemu_st8:
1255 tcg_out_qemu_st(s, args, 0);
1256 break;
1257 case INDEX_op_qemu_st16:
1258 tcg_out_qemu_st(s, args, 1);
1259 break;
1260 case INDEX_op_qemu_st32:
1261 tcg_out_qemu_st(s, args, 2);
1262 break;
1263 case INDEX_op_qemu_st64:
1264 tcg_out_qemu_st(s, args, 3);
1265 break;
1266
1267 case INDEX_op_bswap32_i64:
1268 /* Despite the _i64, this is a 32-bit bswap. */
1269 ext = 0;
1270 /* FALLTHRU */
1271 case INDEX_op_bswap64_i64:
1272 case INDEX_op_bswap32_i32:
1273 tcg_out_rev(s, ext, a0, a1);
1274 break;
1275 case INDEX_op_bswap16_i64:
1276 case INDEX_op_bswap16_i32:
1277 tcg_out_rev16(s, 0, a0, a1);
1278 break;
1279
1280 case INDEX_op_ext8s_i64:
1281 case INDEX_op_ext8s_i32:
1282 tcg_out_sxt(s, ext, 0, a0, a1);
1283 break;
1284 case INDEX_op_ext16s_i64:
1285 case INDEX_op_ext16s_i32:
1286 tcg_out_sxt(s, ext, 1, a0, a1);
1287 break;
1288 case INDEX_op_ext32s_i64:
1289 tcg_out_sxt(s, 1, 2, a0, a1);
1290 break;
1291 case INDEX_op_ext8u_i64:
1292 case INDEX_op_ext8u_i32:
1293 tcg_out_uxt(s, 0, a0, a1);
1294 break;
1295 case INDEX_op_ext16u_i64:
1296 case INDEX_op_ext16u_i32:
1297 tcg_out_uxt(s, 1, a0, a1);
1298 break;
1299 case INDEX_op_ext32u_i64:
1300 tcg_out_movr(s, 0, a0, a1);
1301 break;
1302
1303 case INDEX_op_mov_i64:
1304 case INDEX_op_mov_i32:
1305 case INDEX_op_movi_i64:
1306 case INDEX_op_movi_i32:
1307 /* Always implemented with tcg_out_mov/i, never with tcg_out_op. */
1308 default:
1309 /* Opcode not implemented. */
1310 tcg_abort();
1311 }
1312 }
1313
1314 static const TCGTargetOpDef aarch64_op_defs[] = {
1315 { INDEX_op_exit_tb, { } },
1316 { INDEX_op_goto_tb, { } },
1317 { INDEX_op_call, { "ri" } },
1318 { INDEX_op_br, { } },
1319
1320 { INDEX_op_mov_i32, { "r", "r" } },
1321 { INDEX_op_mov_i64, { "r", "r" } },
1322
1323 { INDEX_op_movi_i32, { "r" } },
1324 { INDEX_op_movi_i64, { "r" } },
1325
1326 { INDEX_op_ld8u_i32, { "r", "r" } },
1327 { INDEX_op_ld8s_i32, { "r", "r" } },
1328 { INDEX_op_ld16u_i32, { "r", "r" } },
1329 { INDEX_op_ld16s_i32, { "r", "r" } },
1330 { INDEX_op_ld_i32, { "r", "r" } },
1331 { INDEX_op_ld8u_i64, { "r", "r" } },
1332 { INDEX_op_ld8s_i64, { "r", "r" } },
1333 { INDEX_op_ld16u_i64, { "r", "r" } },
1334 { INDEX_op_ld16s_i64, { "r", "r" } },
1335 { INDEX_op_ld32u_i64, { "r", "r" } },
1336 { INDEX_op_ld32s_i64, { "r", "r" } },
1337 { INDEX_op_ld_i64, { "r", "r" } },
1338
1339 { INDEX_op_st8_i32, { "r", "r" } },
1340 { INDEX_op_st16_i32, { "r", "r" } },
1341 { INDEX_op_st_i32, { "r", "r" } },
1342 { INDEX_op_st8_i64, { "r", "r" } },
1343 { INDEX_op_st16_i64, { "r", "r" } },
1344 { INDEX_op_st32_i64, { "r", "r" } },
1345 { INDEX_op_st_i64, { "r", "r" } },
1346
1347 { INDEX_op_add_i32, { "r", "r", "r" } },
1348 { INDEX_op_add_i64, { "r", "r", "r" } },
1349 { INDEX_op_sub_i32, { "r", "r", "r" } },
1350 { INDEX_op_sub_i64, { "r", "r", "r" } },
1351 { INDEX_op_mul_i32, { "r", "r", "r" } },
1352 { INDEX_op_mul_i64, { "r", "r", "r" } },
1353 { INDEX_op_and_i32, { "r", "r", "r" } },
1354 { INDEX_op_and_i64, { "r", "r", "r" } },
1355 { INDEX_op_or_i32, { "r", "r", "r" } },
1356 { INDEX_op_or_i64, { "r", "r", "r" } },
1357 { INDEX_op_xor_i32, { "r", "r", "r" } },
1358 { INDEX_op_xor_i64, { "r", "r", "r" } },
1359
1360 { INDEX_op_shl_i32, { "r", "r", "ri" } },
1361 { INDEX_op_shr_i32, { "r", "r", "ri" } },
1362 { INDEX_op_sar_i32, { "r", "r", "ri" } },
1363 { INDEX_op_rotl_i32, { "r", "r", "ri" } },
1364 { INDEX_op_rotr_i32, { "r", "r", "ri" } },
1365 { INDEX_op_shl_i64, { "r", "r", "ri" } },
1366 { INDEX_op_shr_i64, { "r", "r", "ri" } },
1367 { INDEX_op_sar_i64, { "r", "r", "ri" } },
1368 { INDEX_op_rotl_i64, { "r", "r", "ri" } },
1369 { INDEX_op_rotr_i64, { "r", "r", "ri" } },
1370
1371 { INDEX_op_brcond_i32, { "r", "r" } },
1372 { INDEX_op_setcond_i32, { "r", "r", "r" } },
1373 { INDEX_op_brcond_i64, { "r", "r" } },
1374 { INDEX_op_setcond_i64, { "r", "r", "r" } },
1375
1376 { INDEX_op_qemu_ld8u, { "r", "l" } },
1377 { INDEX_op_qemu_ld8s, { "r", "l" } },
1378 { INDEX_op_qemu_ld16u, { "r", "l" } },
1379 { INDEX_op_qemu_ld16s, { "r", "l" } },
1380 { INDEX_op_qemu_ld32u, { "r", "l" } },
1381 { INDEX_op_qemu_ld32s, { "r", "l" } },
1382
1383 { INDEX_op_qemu_ld32, { "r", "l" } },
1384 { INDEX_op_qemu_ld64, { "r", "l" } },
1385
1386 { INDEX_op_qemu_st8, { "l", "l" } },
1387 { INDEX_op_qemu_st16, { "l", "l" } },
1388 { INDEX_op_qemu_st32, { "l", "l" } },
1389 { INDEX_op_qemu_st64, { "l", "l" } },
1390
1391 { INDEX_op_bswap16_i32, { "r", "r" } },
1392 { INDEX_op_bswap32_i32, { "r", "r" } },
1393 { INDEX_op_bswap16_i64, { "r", "r" } },
1394 { INDEX_op_bswap32_i64, { "r", "r" } },
1395 { INDEX_op_bswap64_i64, { "r", "r" } },
1396
1397 { INDEX_op_ext8s_i32, { "r", "r" } },
1398 { INDEX_op_ext16s_i32, { "r", "r" } },
1399 { INDEX_op_ext8u_i32, { "r", "r" } },
1400 { INDEX_op_ext16u_i32, { "r", "r" } },
1401
1402 { INDEX_op_ext8s_i64, { "r", "r" } },
1403 { INDEX_op_ext16s_i64, { "r", "r" } },
1404 { INDEX_op_ext32s_i64, { "r", "r" } },
1405 { INDEX_op_ext8u_i64, { "r", "r" } },
1406 { INDEX_op_ext16u_i64, { "r", "r" } },
1407 { INDEX_op_ext32u_i64, { "r", "r" } },
1408
1409 { -1 },
1410 };
1411
1412 static void tcg_target_init(TCGContext *s)
1413 {
1414 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
1415 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
1416
1417 tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1418 (1 << TCG_REG_X0) | (1 << TCG_REG_X1) |
1419 (1 << TCG_REG_X2) | (1 << TCG_REG_X3) |
1420 (1 << TCG_REG_X4) | (1 << TCG_REG_X5) |
1421 (1 << TCG_REG_X6) | (1 << TCG_REG_X7) |
1422 (1 << TCG_REG_X8) | (1 << TCG_REG_X9) |
1423 (1 << TCG_REG_X10) | (1 << TCG_REG_X11) |
1424 (1 << TCG_REG_X12) | (1 << TCG_REG_X13) |
1425 (1 << TCG_REG_X14) | (1 << TCG_REG_X15) |
1426 (1 << TCG_REG_X16) | (1 << TCG_REG_X17) |
1427 (1 << TCG_REG_X18));
1428
1429 tcg_regset_clear(s->reserved_regs);
1430 tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
1431 tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP);
1432 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
1433 tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */
1434
1435 tcg_add_target_add_op_defs(aarch64_op_defs);
1436 }
1437
1438 static void tcg_target_qemu_prologue(TCGContext *s)
1439 {
1440 /* NB: frame sizes are in 16 byte stack units! */
1441 int frame_size_callee_saved, frame_size_tcg_locals;
1442 TCGReg r;
1443
1444 /* save pairs (FP, LR) and (X19, X20) .. (X27, X28) */
1445 frame_size_callee_saved = (1) + (TCG_REG_X28 - TCG_REG_X19) / 2 + 1;
1446
1447 /* frame size requirement for TCG local variables */
1448 frame_size_tcg_locals = TCG_STATIC_CALL_ARGS_SIZE
1449 + CPU_TEMP_BUF_NLONGS * sizeof(long)
1450 + (TCG_TARGET_STACK_ALIGN - 1);
1451 frame_size_tcg_locals &= ~(TCG_TARGET_STACK_ALIGN - 1);
1452 frame_size_tcg_locals /= TCG_TARGET_STACK_ALIGN;
1453
1454 /* push (FP, LR) and update sp */
1455 tcg_out_push_pair(s, TCG_REG_SP,
1456 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1457
1458 /* FP -> callee_saved */
1459 tcg_out_movr_sp(s, 1, TCG_REG_FP, TCG_REG_SP);
1460
1461 /* store callee-preserved regs x19..x28 using FP -> callee_saved */
1462 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1463 int idx = (r - TCG_REG_X19) / 2 + 1;
1464 tcg_out_store_pair(s, TCG_REG_FP, r, r + 1, idx);
1465 }
1466
1467 /* make stack space for TCG locals */
1468 tcg_out_subi(s, 1, TCG_REG_SP, TCG_REG_SP,
1469 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1470 /* inform TCG about how to find TCG locals with register, offset, size */
1471 tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE,
1472 CPU_TEMP_BUF_NLONGS * sizeof(long));
1473
1474 #if defined(CONFIG_USE_GUEST_BASE)
1475 if (GUEST_BASE) {
1476 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, GUEST_BASE);
1477 tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE);
1478 }
1479 #endif
1480
1481 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
1482 tcg_out_gotor(s, tcg_target_call_iarg_regs[1]);
1483
1484 tb_ret_addr = s->code_ptr;
1485
1486 /* remove TCG locals stack space */
1487 tcg_out_addi(s, 1, TCG_REG_SP, TCG_REG_SP,
1488 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1489
1490 /* restore registers x19..x28.
1491 FP must be preserved, so it still points to callee_saved area */
1492 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1493 int idx = (r - TCG_REG_X19) / 2 + 1;
1494 tcg_out_load_pair(s, TCG_REG_FP, r, r + 1, idx);
1495 }
1496
1497 /* pop (FP, LR), restore SP to previous frame, return */
1498 tcg_out_pop_pair(s, TCG_REG_SP,
1499 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1500 tcg_out_ret(s);
1501 }