Merge remote-tracking branch 'bonzini/iommu-for-anthony' into staging
[qemu/ar7.git] / tcg / aarch64 / tcg-target.c
blob562a549dab82fa9c013a3d0eda0daf4de0f24211
1 /*
2 * Initial TCG Implementation for aarch64
4 * Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
5 * Written by Claudio Fontana
7 * This work is licensed under the terms of the GNU GPL, version 2 or
8 * (at your option) any later version.
10 * See the COPYING file in the top-level directory for details.
13 #include "qemu/bitops.h"
15 #ifndef NDEBUG
16 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
17 "%x0", "%x1", "%x2", "%x3", "%x4", "%x5", "%x6", "%x7",
18 "%x8", "%x9", "%x10", "%x11", "%x12", "%x13", "%x14", "%x15",
19 "%x16", "%x17", "%x18", "%x19", "%x20", "%x21", "%x22", "%x23",
20 "%x24", "%x25", "%x26", "%x27", "%x28",
21 "%fp", /* frame pointer */
22 "%lr", /* link register */
23 "%sp", /* stack pointer */
25 #endif /* NDEBUG */
27 #ifdef TARGET_WORDS_BIGENDIAN
28 #define TCG_LDST_BSWAP 1
29 #else
30 #define TCG_LDST_BSWAP 0
31 #endif
33 static const int tcg_target_reg_alloc_order[] = {
34 TCG_REG_X20, TCG_REG_X21, TCG_REG_X22, TCG_REG_X23,
35 TCG_REG_X24, TCG_REG_X25, TCG_REG_X26, TCG_REG_X27,
36 TCG_REG_X28, /* we will reserve this for GUEST_BASE if configured */
38 TCG_REG_X9, TCG_REG_X10, TCG_REG_X11, TCG_REG_X12,
39 TCG_REG_X13, TCG_REG_X14, TCG_REG_X15,
40 TCG_REG_X16, TCG_REG_X17,
42 TCG_REG_X18, TCG_REG_X19, /* will not use these, see tcg_target_init */
44 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,
47 TCG_REG_X8, /* will not use, see tcg_target_init */
50 static const int tcg_target_call_iarg_regs[8] = {
51 TCG_REG_X0, TCG_REG_X1, TCG_REG_X2, TCG_REG_X3,
52 TCG_REG_X4, TCG_REG_X5, TCG_REG_X6, TCG_REG_X7
54 static const int tcg_target_call_oarg_regs[1] = {
55 TCG_REG_X0
58 #define TCG_REG_TMP TCG_REG_X8
60 #ifndef CONFIG_SOFTMMU
61 # if defined(CONFIG_USE_GUEST_BASE)
62 # define TCG_REG_GUEST_BASE TCG_REG_X28
63 # else
64 # define TCG_REG_GUEST_BASE TCG_REG_XZR
65 # endif
66 #endif
68 static inline void reloc_pc26(void *code_ptr, tcg_target_long target)
70 tcg_target_long offset; uint32_t insn;
71 offset = (target - (tcg_target_long)code_ptr) / 4;
72 /* read instruction, mask away previous PC_REL26 parameter contents,
73 set the proper offset, then write back the instruction. */
74 insn = *(uint32_t *)code_ptr;
75 insn = deposit32(insn, 0, 26, offset);
76 *(uint32_t *)code_ptr = insn;
79 static inline void reloc_pc19(void *code_ptr, tcg_target_long target)
81 tcg_target_long offset; uint32_t insn;
82 offset = (target - (tcg_target_long)code_ptr) / 4;
83 /* read instruction, mask away previous PC_REL19 parameter contents,
84 set the proper offset, then write back the instruction. */
85 insn = *(uint32_t *)code_ptr;
86 insn = deposit32(insn, 5, 19, offset);
87 *(uint32_t *)code_ptr = insn;
90 static inline void patch_reloc(uint8_t *code_ptr, int type,
91 tcg_target_long value, tcg_target_long addend)
93 value += addend;
95 switch (type) {
96 case R_AARCH64_JUMP26:
97 case R_AARCH64_CALL26:
98 reloc_pc26(code_ptr, value);
99 break;
100 case R_AARCH64_CONDBR19:
101 reloc_pc19(code_ptr, value);
102 break;
104 default:
105 tcg_abort();
109 /* parse target specific constraints */
110 static int target_parse_constraint(TCGArgConstraint *ct,
111 const char **pct_str)
113 const char *ct_str = *pct_str;
115 switch (ct_str[0]) {
116 case 'r':
117 ct->ct |= TCG_CT_REG;
118 tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1);
119 break;
120 case 'l': /* qemu_ld / qemu_st address, data_reg */
121 ct->ct |= TCG_CT_REG;
122 tcg_regset_set32(ct->u.regs, 0, (1ULL << TCG_TARGET_NB_REGS) - 1);
123 #ifdef CONFIG_SOFTMMU
124 /* x0 and x1 will be overwritten when reading the tlb entry,
125 and x2, and x3 for helper args, better to avoid using them. */
126 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X0);
127 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X1);
128 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X2);
129 tcg_regset_reset_reg(ct->u.regs, TCG_REG_X3);
130 #endif
131 break;
132 default:
133 return -1;
136 ct_str++;
137 *pct_str = ct_str;
138 return 0;
141 static inline int tcg_target_const_match(tcg_target_long val,
142 const TCGArgConstraint *arg_ct)
144 int ct = arg_ct->ct;
146 if (ct & TCG_CT_CONST) {
147 return 1;
150 return 0;
153 enum aarch64_cond_code {
154 COND_EQ = 0x0,
155 COND_NE = 0x1,
156 COND_CS = 0x2, /* Unsigned greater or equal */
157 COND_HS = COND_CS, /* ALIAS greater or equal */
158 COND_CC = 0x3, /* Unsigned less than */
159 COND_LO = COND_CC, /* ALIAS Lower */
160 COND_MI = 0x4, /* Negative */
161 COND_PL = 0x5, /* Zero or greater */
162 COND_VS = 0x6, /* Overflow */
163 COND_VC = 0x7, /* No overflow */
164 COND_HI = 0x8, /* Unsigned greater than */
165 COND_LS = 0x9, /* Unsigned less or equal */
166 COND_GE = 0xa,
167 COND_LT = 0xb,
168 COND_GT = 0xc,
169 COND_LE = 0xd,
170 COND_AL = 0xe,
171 COND_NV = 0xf, /* behaves like COND_AL here */
174 static const enum aarch64_cond_code tcg_cond_to_aarch64[] = {
175 [TCG_COND_EQ] = COND_EQ,
176 [TCG_COND_NE] = COND_NE,
177 [TCG_COND_LT] = COND_LT,
178 [TCG_COND_GE] = COND_GE,
179 [TCG_COND_LE] = COND_LE,
180 [TCG_COND_GT] = COND_GT,
181 /* unsigned */
182 [TCG_COND_LTU] = COND_LO,
183 [TCG_COND_GTU] = COND_HI,
184 [TCG_COND_GEU] = COND_HS,
185 [TCG_COND_LEU] = COND_LS,
188 /* opcodes for LDR / STR instructions with base + simm9 addressing */
189 enum aarch64_ldst_op_data { /* size of the data moved */
190 LDST_8 = 0x38,
191 LDST_16 = 0x78,
192 LDST_32 = 0xb8,
193 LDST_64 = 0xf8,
195 enum aarch64_ldst_op_type { /* type of operation */
196 LDST_ST = 0x0, /* store */
197 LDST_LD = 0x4, /* load */
198 LDST_LD_S_X = 0x8, /* load and sign-extend into Xt */
199 LDST_LD_S_W = 0xc, /* load and sign-extend into Wt */
202 enum aarch64_arith_opc {
203 ARITH_AND = 0x0a,
204 ARITH_ADD = 0x0b,
205 ARITH_OR = 0x2a,
206 ARITH_ADDS = 0x2b,
207 ARITH_XOR = 0x4a,
208 ARITH_SUB = 0x4b,
209 ARITH_ANDS = 0x6a,
210 ARITH_SUBS = 0x6b,
213 enum aarch64_srr_opc {
214 SRR_SHL = 0x0,
215 SRR_SHR = 0x4,
216 SRR_SAR = 0x8,
217 SRR_ROR = 0xc
220 static inline enum aarch64_ldst_op_data
221 aarch64_ldst_get_data(TCGOpcode tcg_op)
223 switch (tcg_op) {
224 case INDEX_op_ld8u_i32:
225 case INDEX_op_ld8s_i32:
226 case INDEX_op_ld8u_i64:
227 case INDEX_op_ld8s_i64:
228 case INDEX_op_st8_i32:
229 case INDEX_op_st8_i64:
230 return LDST_8;
232 case INDEX_op_ld16u_i32:
233 case INDEX_op_ld16s_i32:
234 case INDEX_op_ld16u_i64:
235 case INDEX_op_ld16s_i64:
236 case INDEX_op_st16_i32:
237 case INDEX_op_st16_i64:
238 return LDST_16;
240 case INDEX_op_ld_i32:
241 case INDEX_op_st_i32:
242 case INDEX_op_ld32u_i64:
243 case INDEX_op_ld32s_i64:
244 case INDEX_op_st32_i64:
245 return LDST_32;
247 case INDEX_op_ld_i64:
248 case INDEX_op_st_i64:
249 return LDST_64;
251 default:
252 tcg_abort();
256 static inline enum aarch64_ldst_op_type
257 aarch64_ldst_get_type(TCGOpcode tcg_op)
259 switch (tcg_op) {
260 case INDEX_op_st8_i32:
261 case INDEX_op_st16_i32:
262 case INDEX_op_st8_i64:
263 case INDEX_op_st16_i64:
264 case INDEX_op_st_i32:
265 case INDEX_op_st32_i64:
266 case INDEX_op_st_i64:
267 return LDST_ST;
269 case INDEX_op_ld8u_i32:
270 case INDEX_op_ld16u_i32:
271 case INDEX_op_ld8u_i64:
272 case INDEX_op_ld16u_i64:
273 case INDEX_op_ld_i32:
274 case INDEX_op_ld32u_i64:
275 case INDEX_op_ld_i64:
276 return LDST_LD;
278 case INDEX_op_ld8s_i32:
279 case INDEX_op_ld16s_i32:
280 return LDST_LD_S_W;
282 case INDEX_op_ld8s_i64:
283 case INDEX_op_ld16s_i64:
284 case INDEX_op_ld32s_i64:
285 return LDST_LD_S_X;
287 default:
288 tcg_abort();
292 static inline uint32_t tcg_in32(TCGContext *s)
294 uint32_t v = *(uint32_t *)s->code_ptr;
295 return v;
298 static inline void tcg_out_ldst_9(TCGContext *s,
299 enum aarch64_ldst_op_data op_data,
300 enum aarch64_ldst_op_type op_type,
301 TCGReg rd, TCGReg rn, tcg_target_long offset)
303 /* use LDUR with BASE register with 9bit signed unscaled offset */
304 unsigned int mod, off;
306 if (offset < 0) {
307 off = (256 + offset);
308 mod = 0x1;
309 } else {
310 off = offset;
311 mod = 0x0;
314 mod |= op_type;
315 tcg_out32(s, op_data << 24 | mod << 20 | off << 12 | rn << 5 | rd);
318 static inline void tcg_out_movr(TCGContext *s, int ext, TCGReg rd, TCGReg src)
320 /* register to register move using MOV (shifted register with no shift) */
321 /* using MOV 0x2a0003e0 | (shift).. */
322 unsigned int base = ext ? 0xaa0003e0 : 0x2a0003e0;
323 tcg_out32(s, base | src << 16 | rd);
326 static inline void tcg_out_movi_aux(TCGContext *s,
327 TCGReg rd, uint64_t value)
329 uint32_t half, base, shift, movk = 0;
330 /* construct halfwords of the immediate with MOVZ/MOVK with LSL */
331 /* using MOVZ 0x52800000 | extended reg.. */
332 base = (value > 0xffffffff) ? 0xd2800000 : 0x52800000;
333 /* count trailing zeros in 16 bit steps, mapping 64 to 0. Emit the
334 first MOVZ with the half-word immediate skipping the zeros, with a shift
335 (LSL) equal to this number. Then morph all next instructions into MOVKs.
336 Zero the processed half-word in the value, continue until empty.
337 We build the final result 16bits at a time with up to 4 instructions,
338 but do not emit instructions for 16bit zero holes. */
339 do {
340 shift = ctz64(value) & (63 & -16);
341 half = (value >> shift) & 0xffff;
342 tcg_out32(s, base | movk | shift << 17 | half << 5 | rd);
343 movk = 0x20000000; /* morph next MOVZs into MOVKs */
344 value &= ~(0xffffUL << shift);
345 } while (value);
348 static inline void tcg_out_movi(TCGContext *s, TCGType type,
349 TCGReg rd, tcg_target_long value)
351 if (type == TCG_TYPE_I64) {
352 tcg_out_movi_aux(s, rd, value);
353 } else {
354 tcg_out_movi_aux(s, rd, value & 0xffffffff);
358 static inline void tcg_out_ldst_r(TCGContext *s,
359 enum aarch64_ldst_op_data op_data,
360 enum aarch64_ldst_op_type op_type,
361 TCGReg rd, TCGReg base, TCGReg regoff)
363 /* load from memory to register using base + 64bit register offset */
364 /* using f.e. STR Wt, [Xn, Xm] 0xb8600800|(regoff << 16)|(base << 5)|rd */
365 /* the 0x6000 is for the "no extend field" */
366 tcg_out32(s, 0x00206800
367 | op_data << 24 | op_type << 20 | regoff << 16 | base << 5 | rd);
370 /* solve the whole ldst problem */
371 static inline void tcg_out_ldst(TCGContext *s, enum aarch64_ldst_op_data data,
372 enum aarch64_ldst_op_type type,
373 TCGReg rd, TCGReg rn, tcg_target_long offset)
375 if (offset >= -256 && offset < 256) {
376 tcg_out_ldst_9(s, data, type, rd, rn, offset);
377 } else {
378 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, offset);
379 tcg_out_ldst_r(s, data, type, rd, rn, TCG_REG_TMP);
383 /* mov alias implemented with add immediate, useful to move to/from SP */
384 static inline void tcg_out_movr_sp(TCGContext *s, int ext, TCGReg rd, TCGReg rn)
386 /* using ADD 0x11000000 | (ext) | rn << 5 | rd */
387 unsigned int base = ext ? 0x91000000 : 0x11000000;
388 tcg_out32(s, base | rn << 5 | rd);
391 static inline void tcg_out_mov(TCGContext *s,
392 TCGType type, TCGReg ret, TCGReg arg)
394 if (ret != arg) {
395 tcg_out_movr(s, type == TCG_TYPE_I64, ret, arg);
399 static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
400 TCGReg arg1, tcg_target_long arg2)
402 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_LD,
403 arg, arg1, arg2);
406 static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
407 TCGReg arg1, tcg_target_long arg2)
409 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_ST,
410 arg, arg1, arg2);
413 static inline void tcg_out_arith(TCGContext *s, enum aarch64_arith_opc opc,
414 int ext, TCGReg rd, TCGReg rn, TCGReg rm,
415 int shift_imm)
417 /* Using shifted register arithmetic operations */
418 /* if extended register operation (64bit) just OR with 0x80 << 24 */
419 unsigned int shift, base = ext ? (0x80 | opc) << 24 : opc << 24;
420 if (shift_imm == 0) {
421 shift = 0;
422 } else if (shift_imm > 0) {
423 shift = shift_imm << 10 | 1 << 22;
424 } else /* (shift_imm < 0) */ {
425 shift = (-shift_imm) << 10;
427 tcg_out32(s, base | rm << 16 | shift | rn << 5 | rd);
430 static inline void tcg_out_mul(TCGContext *s, int ext,
431 TCGReg rd, TCGReg rn, TCGReg rm)
433 /* Using MADD 0x1b000000 with Ra = wzr alias MUL 0x1b007c00 */
434 unsigned int base = ext ? 0x9b007c00 : 0x1b007c00;
435 tcg_out32(s, base | rm << 16 | rn << 5 | rd);
438 static inline void tcg_out_shiftrot_reg(TCGContext *s,
439 enum aarch64_srr_opc opc, int ext,
440 TCGReg rd, TCGReg rn, TCGReg rm)
442 /* using 2-source data processing instructions 0x1ac02000 */
443 unsigned int base = ext ? 0x9ac02000 : 0x1ac02000;
444 tcg_out32(s, base | rm << 16 | opc << 8 | rn << 5 | rd);
447 static inline void tcg_out_ubfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
448 unsigned int a, unsigned int b)
450 /* Using UBFM 0x53000000 Wd, Wn, a, b */
451 unsigned int base = ext ? 0xd3400000 : 0x53000000;
452 tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd);
455 static inline void tcg_out_sbfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
456 unsigned int a, unsigned int b)
458 /* Using SBFM 0x13000000 Wd, Wn, a, b */
459 unsigned int base = ext ? 0x93400000 : 0x13000000;
460 tcg_out32(s, base | a << 16 | b << 10 | rn << 5 | rd);
463 static inline void tcg_out_extr(TCGContext *s, int ext, TCGReg rd,
464 TCGReg rn, TCGReg rm, unsigned int a)
466 /* Using EXTR 0x13800000 Wd, Wn, Wm, a */
467 unsigned int base = ext ? 0x93c00000 : 0x13800000;
468 tcg_out32(s, base | rm << 16 | a << 10 | rn << 5 | rd);
471 static inline void tcg_out_shl(TCGContext *s, int ext,
472 TCGReg rd, TCGReg rn, unsigned int m)
474 int bits, max;
475 bits = ext ? 64 : 32;
476 max = bits - 1;
477 tcg_out_ubfm(s, ext, rd, rn, bits - (m & max), max - (m & max));
480 static inline void tcg_out_shr(TCGContext *s, int ext,
481 TCGReg rd, TCGReg rn, unsigned int m)
483 int max = ext ? 63 : 31;
484 tcg_out_ubfm(s, ext, rd, rn, m & max, max);
487 static inline void tcg_out_sar(TCGContext *s, int ext,
488 TCGReg rd, TCGReg rn, unsigned int m)
490 int max = ext ? 63 : 31;
491 tcg_out_sbfm(s, ext, rd, rn, m & max, max);
494 static inline void tcg_out_rotr(TCGContext *s, int ext,
495 TCGReg rd, TCGReg rn, unsigned int m)
497 int max = ext ? 63 : 31;
498 tcg_out_extr(s, ext, rd, rn, rn, m & max);
501 static inline void tcg_out_rotl(TCGContext *s, int ext,
502 TCGReg rd, TCGReg rn, unsigned int m)
504 int bits, max;
505 bits = ext ? 64 : 32;
506 max = bits - 1;
507 tcg_out_extr(s, ext, rd, rn, rn, bits - (m & max));
510 static inline void tcg_out_cmp(TCGContext *s, int ext, TCGReg rn, TCGReg rm,
511 int shift_imm)
513 /* Using CMP alias SUBS wzr, Wn, Wm */
514 tcg_out_arith(s, ARITH_SUBS, ext, TCG_REG_XZR, rn, rm, shift_imm);
517 static inline void tcg_out_cset(TCGContext *s, int ext, TCGReg rd, TCGCond c)
519 /* Using CSET alias of CSINC 0x1a800400 Xd, XZR, XZR, invert(cond) */
520 unsigned int base = ext ? 0x9a9f07e0 : 0x1a9f07e0;
521 tcg_out32(s, base | tcg_cond_to_aarch64[tcg_invert_cond(c)] << 12 | rd);
524 static inline void tcg_out_goto(TCGContext *s, tcg_target_long target)
526 tcg_target_long offset;
527 offset = (target - (tcg_target_long)s->code_ptr) / 4;
529 if (offset < -0x02000000 || offset >= 0x02000000) {
530 /* out of 26bit range */
531 tcg_abort();
534 tcg_out32(s, 0x14000000 | (offset & 0x03ffffff));
537 static inline void tcg_out_goto_noaddr(TCGContext *s)
539 /* We pay attention here to not modify the branch target by
540 reading from the buffer. This ensure that caches and memory are
541 kept coherent during retranslation.
542 Mask away possible garbage in the high bits for the first translation,
543 while keeping the offset bits for retranslation. */
544 uint32_t insn;
545 insn = (tcg_in32(s) & 0x03ffffff) | 0x14000000;
546 tcg_out32(s, insn);
549 static inline void tcg_out_goto_cond_noaddr(TCGContext *s, TCGCond c)
551 /* see comments in tcg_out_goto_noaddr */
552 uint32_t insn;
553 insn = tcg_in32(s) & (0x07ffff << 5);
554 insn |= 0x54000000 | tcg_cond_to_aarch64[c];
555 tcg_out32(s, insn);
558 static inline void tcg_out_goto_cond(TCGContext *s, TCGCond c,
559 tcg_target_long target)
561 tcg_target_long offset;
562 offset = (target - (tcg_target_long)s->code_ptr) / 4;
564 if (offset < -0x40000 || offset >= 0x40000) {
565 /* out of 19bit range */
566 tcg_abort();
569 offset &= 0x7ffff;
570 tcg_out32(s, 0x54000000 | tcg_cond_to_aarch64[c] | offset << 5);
573 static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
575 tcg_out32(s, 0xd63f0000 | reg << 5);
578 static inline void tcg_out_gotor(TCGContext *s, TCGReg reg)
580 tcg_out32(s, 0xd61f0000 | reg << 5);
583 static inline void tcg_out_call(TCGContext *s, tcg_target_long target)
585 tcg_target_long offset;
587 offset = (target - (tcg_target_long)s->code_ptr) / 4;
589 if (offset < -0x02000000 || offset >= 0x02000000) { /* out of 26bit rng */
590 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, target);
591 tcg_out_callr(s, TCG_REG_TMP);
592 } else {
593 tcg_out32(s, 0x94000000 | (offset & 0x03ffffff));
597 /* encode a logical immediate, mapping user parameter
598 M=set bits pattern length to S=M-1 */
599 static inline unsigned int
600 aarch64_limm(unsigned int m, unsigned int r)
602 assert(m > 0);
603 return r << 16 | (m - 1) << 10;
606 /* test a register against an immediate bit pattern made of
607 M set bits rotated right by R.
608 Examples:
609 to test a 32/64 reg against 0x00000007, pass M = 3, R = 0.
610 to test a 32/64 reg against 0x000000ff, pass M = 8, R = 0.
611 to test a 32bit reg against 0xff000000, pass M = 8, R = 8.
612 to test a 32bit reg against 0xff0000ff, pass M = 16, R = 8.
614 static inline void tcg_out_tst(TCGContext *s, int ext, TCGReg rn,
615 unsigned int m, unsigned int r)
617 /* using TST alias of ANDS XZR, Xn,#bimm64 0x7200001f */
618 unsigned int base = ext ? 0xf240001f : 0x7200001f;
619 tcg_out32(s, base | aarch64_limm(m, r) | rn << 5);
622 /* and a register with a bit pattern, similarly to TST, no flags change */
623 static inline void tcg_out_andi(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
624 unsigned int m, unsigned int r)
626 /* using AND 0x12000000 */
627 unsigned int base = ext ? 0x92400000 : 0x12000000;
628 tcg_out32(s, base | aarch64_limm(m, r) | rn << 5 | rd);
631 static inline void tcg_out_ret(TCGContext *s)
633 /* emit RET { LR } */
634 tcg_out32(s, 0xd65f03c0);
637 void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr)
639 tcg_target_long target, offset;
640 target = (tcg_target_long)addr;
641 offset = (target - (tcg_target_long)jmp_addr) / 4;
643 if (offset < -0x02000000 || offset >= 0x02000000) {
644 /* out of 26bit range */
645 tcg_abort();
648 patch_reloc((uint8_t *)jmp_addr, R_AARCH64_JUMP26, target, 0);
649 flush_icache_range(jmp_addr, jmp_addr + 4);
652 static inline void tcg_out_goto_label(TCGContext *s, int label_index)
654 TCGLabel *l = &s->labels[label_index];
656 if (!l->has_value) {
657 tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, label_index, 0);
658 tcg_out_goto_noaddr(s);
659 } else {
660 tcg_out_goto(s, l->u.value);
664 static inline void tcg_out_goto_label_cond(TCGContext *s,
665 TCGCond c, int label_index)
667 TCGLabel *l = &s->labels[label_index];
669 if (!l->has_value) {
670 tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, label_index, 0);
671 tcg_out_goto_cond_noaddr(s, c);
672 } else {
673 tcg_out_goto_cond(s, c, l->u.value);
677 static inline void tcg_out_rev(TCGContext *s, int ext, TCGReg rd, TCGReg rm)
679 /* using REV 0x5ac00800 */
680 unsigned int base = ext ? 0xdac00c00 : 0x5ac00800;
681 tcg_out32(s, base | rm << 5 | rd);
684 static inline void tcg_out_rev16(TCGContext *s, int ext, TCGReg rd, TCGReg rm)
686 /* using REV16 0x5ac00400 */
687 unsigned int base = ext ? 0xdac00400 : 0x5ac00400;
688 tcg_out32(s, base | rm << 5 | rd);
691 static inline void tcg_out_sxt(TCGContext *s, int ext, int s_bits,
692 TCGReg rd, TCGReg rn)
694 /* using ALIASes SXTB 0x13001c00, SXTH 0x13003c00, SXTW 0x93407c00
695 of SBFM Xd, Xn, #0, #7|15|31 */
696 int bits = 8 * (1 << s_bits) - 1;
697 tcg_out_sbfm(s, ext, rd, rn, 0, bits);
700 static inline void tcg_out_uxt(TCGContext *s, int s_bits,
701 TCGReg rd, TCGReg rn)
703 /* using ALIASes UXTB 0x53001c00, UXTH 0x53003c00
704 of UBFM Wd, Wn, #0, #7|15 */
705 int bits = 8 * (1 << s_bits) - 1;
706 tcg_out_ubfm(s, 0, rd, rn, 0, bits);
709 #ifdef CONFIG_SOFTMMU
710 #include "exec/softmmu_defs.h"
712 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
713 int mmu_idx) */
714 static const void * const qemu_ld_helpers[4] = {
715 helper_ldb_mmu,
716 helper_ldw_mmu,
717 helper_ldl_mmu,
718 helper_ldq_mmu,
721 /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
722 uintxx_t val, int mmu_idx) */
723 static const void * const qemu_st_helpers[4] = {
724 helper_stb_mmu,
725 helper_stw_mmu,
726 helper_stl_mmu,
727 helper_stq_mmu,
730 #else /* !CONFIG_SOFTMMU */
732 static void tcg_out_qemu_ld_direct(TCGContext *s, int opc, TCGReg data_r,
733 TCGReg addr_r, TCGReg off_r)
735 switch (opc) {
736 case 0:
737 tcg_out_ldst_r(s, LDST_8, LDST_LD, data_r, addr_r, off_r);
738 break;
739 case 0 | 4:
740 tcg_out_ldst_r(s, LDST_8, LDST_LD_S_X, data_r, addr_r, off_r);
741 break;
742 case 1:
743 tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r);
744 if (TCG_LDST_BSWAP) {
745 tcg_out_rev16(s, 0, data_r, data_r);
747 break;
748 case 1 | 4:
749 if (TCG_LDST_BSWAP) {
750 tcg_out_ldst_r(s, LDST_16, LDST_LD, data_r, addr_r, off_r);
751 tcg_out_rev16(s, 0, data_r, data_r);
752 tcg_out_sxt(s, 1, 1, data_r, data_r);
753 } else {
754 tcg_out_ldst_r(s, LDST_16, LDST_LD_S_X, data_r, addr_r, off_r);
756 break;
757 case 2:
758 tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r);
759 if (TCG_LDST_BSWAP) {
760 tcg_out_rev(s, 0, data_r, data_r);
762 break;
763 case 2 | 4:
764 if (TCG_LDST_BSWAP) {
765 tcg_out_ldst_r(s, LDST_32, LDST_LD, data_r, addr_r, off_r);
766 tcg_out_rev(s, 0, data_r, data_r);
767 tcg_out_sxt(s, 1, 2, data_r, data_r);
768 } else {
769 tcg_out_ldst_r(s, LDST_32, LDST_LD_S_X, data_r, addr_r, off_r);
771 break;
772 case 3:
773 tcg_out_ldst_r(s, LDST_64, LDST_LD, data_r, addr_r, off_r);
774 if (TCG_LDST_BSWAP) {
775 tcg_out_rev(s, 1, data_r, data_r);
777 break;
778 default:
779 tcg_abort();
783 static void tcg_out_qemu_st_direct(TCGContext *s, int opc, TCGReg data_r,
784 TCGReg addr_r, TCGReg off_r)
786 switch (opc) {
787 case 0:
788 tcg_out_ldst_r(s, LDST_8, LDST_ST, data_r, addr_r, off_r);
789 break;
790 case 1:
791 if (TCG_LDST_BSWAP) {
792 tcg_out_rev16(s, 0, TCG_REG_TMP, data_r);
793 tcg_out_ldst_r(s, LDST_16, LDST_ST, TCG_REG_TMP, addr_r, off_r);
794 } else {
795 tcg_out_ldst_r(s, LDST_16, LDST_ST, data_r, addr_r, off_r);
797 break;
798 case 2:
799 if (TCG_LDST_BSWAP) {
800 tcg_out_rev(s, 0, TCG_REG_TMP, data_r);
801 tcg_out_ldst_r(s, LDST_32, LDST_ST, TCG_REG_TMP, addr_r, off_r);
802 } else {
803 tcg_out_ldst_r(s, LDST_32, LDST_ST, data_r, addr_r, off_r);
805 break;
806 case 3:
807 if (TCG_LDST_BSWAP) {
808 tcg_out_rev(s, 1, TCG_REG_TMP, data_r);
809 tcg_out_ldst_r(s, LDST_64, LDST_ST, TCG_REG_TMP, addr_r, off_r);
810 } else {
811 tcg_out_ldst_r(s, LDST_64, LDST_ST, data_r, addr_r, off_r);
813 break;
814 default:
815 tcg_abort();
818 #endif /* CONFIG_SOFTMMU */
820 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
822 TCGReg addr_reg, data_reg;
823 #ifdef CONFIG_SOFTMMU
824 int mem_index, s_bits;
825 #endif
826 data_reg = args[0];
827 addr_reg = args[1];
829 #ifdef CONFIG_SOFTMMU
830 mem_index = args[2];
831 s_bits = opc & 3;
833 /* TODO: insert TLB lookup here */
835 /* all arguments passed via registers */
836 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
837 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg);
838 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, mem_index);
839 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
840 (tcg_target_long)qemu_ld_helpers[s_bits]);
841 tcg_out_callr(s, TCG_REG_TMP);
843 if (opc & 0x04) { /* sign extend */
844 tcg_out_sxt(s, 1, s_bits, data_reg, TCG_REG_X0);
845 } else {
846 tcg_out_movr(s, 1, data_reg, TCG_REG_X0);
849 #else /* !CONFIG_SOFTMMU */
850 tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg,
851 GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
852 #endif /* CONFIG_SOFTMMU */
855 static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
857 TCGReg addr_reg, data_reg;
858 #ifdef CONFIG_SOFTMMU
859 int mem_index, s_bits;
860 #endif
861 data_reg = args[0];
862 addr_reg = args[1];
864 #ifdef CONFIG_SOFTMMU
865 mem_index = args[2];
866 s_bits = opc & 3;
868 /* TODO: insert TLB lookup here */
870 /* all arguments passed via registers */
871 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
872 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg);
873 tcg_out_movr(s, 1, TCG_REG_X2, data_reg);
874 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, mem_index);
875 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
876 (tcg_target_long)qemu_st_helpers[s_bits]);
877 tcg_out_callr(s, TCG_REG_TMP);
879 #else /* !CONFIG_SOFTMMU */
880 tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg,
881 GUEST_BASE ? TCG_REG_GUEST_BASE : TCG_REG_XZR);
882 #endif /* CONFIG_SOFTMMU */
885 static uint8_t *tb_ret_addr;
887 /* callee stack use example:
888 stp x29, x30, [sp,#-32]!
889 mov x29, sp
890 stp x1, x2, [sp,#16]
892 ldp x1, x2, [sp,#16]
893 ldp x29, x30, [sp],#32
897 /* push r1 and r2, and alloc stack space for a total of
898 alloc_n elements (1 element=16 bytes, must be between 1 and 31. */
899 static inline void tcg_out_push_pair(TCGContext *s, TCGReg addr,
900 TCGReg r1, TCGReg r2, int alloc_n)
902 /* using indexed scaled simm7 STP 0x28800000 | (ext) | 0x01000000 (pre-idx)
903 | alloc_n * (-1) << 16 | r2 << 10 | addr << 5 | r1 */
904 assert(alloc_n > 0 && alloc_n < 0x20);
905 alloc_n = (-alloc_n) & 0x3f;
906 tcg_out32(s, 0xa9800000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
909 /* dealloc stack space for a total of alloc_n elements and pop r1, r2. */
910 static inline void tcg_out_pop_pair(TCGContext *s, TCGReg addr,
911 TCGReg r1, TCGReg r2, int alloc_n)
913 /* using indexed scaled simm7 LDP 0x28c00000 | (ext) | nothing (post-idx)
914 | alloc_n << 16 | r2 << 10 | addr << 5 | r1 */
915 assert(alloc_n > 0 && alloc_n < 0x20);
916 tcg_out32(s, 0xa8c00000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
919 static inline void tcg_out_store_pair(TCGContext *s, TCGReg addr,
920 TCGReg r1, TCGReg r2, int idx)
922 /* using register pair offset simm7 STP 0x29000000 | (ext)
923 | idx << 16 | r2 << 10 | addr << 5 | r1 */
924 assert(idx > 0 && idx < 0x20);
925 tcg_out32(s, 0xa9000000 | idx << 16 | r2 << 10 | addr << 5 | r1);
928 static inline void tcg_out_load_pair(TCGContext *s, TCGReg addr,
929 TCGReg r1, TCGReg r2, int idx)
931 /* using register pair offset simm7 LDP 0x29400000 | (ext)
932 | idx << 16 | r2 << 10 | addr << 5 | r1 */
933 assert(idx > 0 && idx < 0x20);
934 tcg_out32(s, 0xa9400000 | idx << 16 | r2 << 10 | addr << 5 | r1);
937 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
938 const TCGArg *args, const int *const_args)
940 /* ext will be set in the switch below, which will fall through to the
941 common code. It triggers the use of extended regs where appropriate. */
942 int ext = 0;
944 switch (opc) {
945 case INDEX_op_exit_tb:
946 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, args[0]);
947 tcg_out_goto(s, (tcg_target_long)tb_ret_addr);
948 break;
950 case INDEX_op_goto_tb:
951 #ifndef USE_DIRECT_JUMP
952 #error "USE_DIRECT_JUMP required for aarch64"
953 #endif
954 assert(s->tb_jmp_offset != NULL); /* consistency for USE_DIRECT_JUMP */
955 s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
956 /* actual branch destination will be patched by
957 aarch64_tb_set_jmp_target later, beware retranslation. */
958 tcg_out_goto_noaddr(s);
959 s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
960 break;
962 case INDEX_op_call:
963 if (const_args[0]) {
964 tcg_out_call(s, args[0]);
965 } else {
966 tcg_out_callr(s, args[0]);
968 break;
970 case INDEX_op_br:
971 tcg_out_goto_label(s, args[0]);
972 break;
974 case INDEX_op_ld_i32:
975 case INDEX_op_ld_i64:
976 case INDEX_op_st_i32:
977 case INDEX_op_st_i64:
978 case INDEX_op_ld8u_i32:
979 case INDEX_op_ld8s_i32:
980 case INDEX_op_ld16u_i32:
981 case INDEX_op_ld16s_i32:
982 case INDEX_op_ld8u_i64:
983 case INDEX_op_ld8s_i64:
984 case INDEX_op_ld16u_i64:
985 case INDEX_op_ld16s_i64:
986 case INDEX_op_ld32u_i64:
987 case INDEX_op_ld32s_i64:
988 case INDEX_op_st8_i32:
989 case INDEX_op_st8_i64:
990 case INDEX_op_st16_i32:
991 case INDEX_op_st16_i64:
992 case INDEX_op_st32_i64:
993 tcg_out_ldst(s, aarch64_ldst_get_data(opc), aarch64_ldst_get_type(opc),
994 args[0], args[1], args[2]);
995 break;
997 case INDEX_op_mov_i64:
998 ext = 1; /* fall through */
999 case INDEX_op_mov_i32:
1000 tcg_out_movr(s, ext, args[0], args[1]);
1001 break;
1003 case INDEX_op_movi_i64:
1004 tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
1005 break;
1006 case INDEX_op_movi_i32:
1007 tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
1008 break;
1010 case INDEX_op_add_i64:
1011 ext = 1; /* fall through */
1012 case INDEX_op_add_i32:
1013 tcg_out_arith(s, ARITH_ADD, ext, args[0], args[1], args[2], 0);
1014 break;
1016 case INDEX_op_sub_i64:
1017 ext = 1; /* fall through */
1018 case INDEX_op_sub_i32:
1019 tcg_out_arith(s, ARITH_SUB, ext, args[0], args[1], args[2], 0);
1020 break;
1022 case INDEX_op_and_i64:
1023 ext = 1; /* fall through */
1024 case INDEX_op_and_i32:
1025 tcg_out_arith(s, ARITH_AND, ext, args[0], args[1], args[2], 0);
1026 break;
1028 case INDEX_op_or_i64:
1029 ext = 1; /* fall through */
1030 case INDEX_op_or_i32:
1031 tcg_out_arith(s, ARITH_OR, ext, args[0], args[1], args[2], 0);
1032 break;
1034 case INDEX_op_xor_i64:
1035 ext = 1; /* fall through */
1036 case INDEX_op_xor_i32:
1037 tcg_out_arith(s, ARITH_XOR, ext, args[0], args[1], args[2], 0);
1038 break;
1040 case INDEX_op_mul_i64:
1041 ext = 1; /* fall through */
1042 case INDEX_op_mul_i32:
1043 tcg_out_mul(s, ext, args[0], args[1], args[2]);
1044 break;
1046 case INDEX_op_shl_i64:
1047 ext = 1; /* fall through */
1048 case INDEX_op_shl_i32:
1049 if (const_args[2]) { /* LSL / UBFM Wd, Wn, (32 - m) */
1050 tcg_out_shl(s, ext, args[0], args[1], args[2]);
1051 } else { /* LSL / LSLV */
1052 tcg_out_shiftrot_reg(s, SRR_SHL, ext, args[0], args[1], args[2]);
1054 break;
1056 case INDEX_op_shr_i64:
1057 ext = 1; /* fall through */
1058 case INDEX_op_shr_i32:
1059 if (const_args[2]) { /* LSR / UBFM Wd, Wn, m, 31 */
1060 tcg_out_shr(s, ext, args[0], args[1], args[2]);
1061 } else { /* LSR / LSRV */
1062 tcg_out_shiftrot_reg(s, SRR_SHR, ext, args[0], args[1], args[2]);
1064 break;
1066 case INDEX_op_sar_i64:
1067 ext = 1; /* fall through */
1068 case INDEX_op_sar_i32:
1069 if (const_args[2]) { /* ASR / SBFM Wd, Wn, m, 31 */
1070 tcg_out_sar(s, ext, args[0], args[1], args[2]);
1071 } else { /* ASR / ASRV */
1072 tcg_out_shiftrot_reg(s, SRR_SAR, ext, args[0], args[1], args[2]);
1074 break;
1076 case INDEX_op_rotr_i64:
1077 ext = 1; /* fall through */
1078 case INDEX_op_rotr_i32:
1079 if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, m */
1080 tcg_out_rotr(s, ext, args[0], args[1], args[2]);
1081 } else { /* ROR / RORV */
1082 tcg_out_shiftrot_reg(s, SRR_ROR, ext, args[0], args[1], args[2]);
1084 break;
1086 case INDEX_op_rotl_i64:
1087 ext = 1; /* fall through */
1088 case INDEX_op_rotl_i32: /* same as rotate right by (32 - m) */
1089 if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, 32 - m */
1090 tcg_out_rotl(s, ext, args[0], args[1], args[2]);
1091 } else {
1092 tcg_out_arith(s, ARITH_SUB, 0,
1093 TCG_REG_TMP, TCG_REG_XZR, args[2], 0);
1094 tcg_out_shiftrot_reg(s, SRR_ROR, ext,
1095 args[0], args[1], TCG_REG_TMP);
1097 break;
1099 case INDEX_op_brcond_i64:
1100 ext = 1; /* fall through */
1101 case INDEX_op_brcond_i32: /* CMP 0, 1, cond(2), label 3 */
1102 tcg_out_cmp(s, ext, args[0], args[1], 0);
1103 tcg_out_goto_label_cond(s, args[2], args[3]);
1104 break;
1106 case INDEX_op_setcond_i64:
1107 ext = 1; /* fall through */
1108 case INDEX_op_setcond_i32:
1109 tcg_out_cmp(s, ext, args[1], args[2], 0);
1110 tcg_out_cset(s, 0, args[0], args[3]);
1111 break;
1113 case INDEX_op_qemu_ld8u:
1114 tcg_out_qemu_ld(s, args, 0 | 0);
1115 break;
1116 case INDEX_op_qemu_ld8s:
1117 tcg_out_qemu_ld(s, args, 4 | 0);
1118 break;
1119 case INDEX_op_qemu_ld16u:
1120 tcg_out_qemu_ld(s, args, 0 | 1);
1121 break;
1122 case INDEX_op_qemu_ld16s:
1123 tcg_out_qemu_ld(s, args, 4 | 1);
1124 break;
1125 case INDEX_op_qemu_ld32u:
1126 tcg_out_qemu_ld(s, args, 0 | 2);
1127 break;
1128 case INDEX_op_qemu_ld32s:
1129 tcg_out_qemu_ld(s, args, 4 | 2);
1130 break;
1131 case INDEX_op_qemu_ld32:
1132 tcg_out_qemu_ld(s, args, 0 | 2);
1133 break;
1134 case INDEX_op_qemu_ld64:
1135 tcg_out_qemu_ld(s, args, 0 | 3);
1136 break;
1137 case INDEX_op_qemu_st8:
1138 tcg_out_qemu_st(s, args, 0);
1139 break;
1140 case INDEX_op_qemu_st16:
1141 tcg_out_qemu_st(s, args, 1);
1142 break;
1143 case INDEX_op_qemu_st32:
1144 tcg_out_qemu_st(s, args, 2);
1145 break;
1146 case INDEX_op_qemu_st64:
1147 tcg_out_qemu_st(s, args, 3);
1148 break;
1150 case INDEX_op_bswap64_i64:
1151 ext = 1; /* fall through */
1152 case INDEX_op_bswap32_i64:
1153 case INDEX_op_bswap32_i32:
1154 tcg_out_rev(s, ext, args[0], args[1]);
1155 break;
1156 case INDEX_op_bswap16_i64:
1157 case INDEX_op_bswap16_i32:
1158 tcg_out_rev16(s, 0, args[0], args[1]);
1159 break;
1161 case INDEX_op_ext8s_i64:
1162 ext = 1; /* fall through */
1163 case INDEX_op_ext8s_i32:
1164 tcg_out_sxt(s, ext, 0, args[0], args[1]);
1165 break;
1166 case INDEX_op_ext16s_i64:
1167 ext = 1; /* fall through */
1168 case INDEX_op_ext16s_i32:
1169 tcg_out_sxt(s, ext, 1, args[0], args[1]);
1170 break;
1171 case INDEX_op_ext32s_i64:
1172 tcg_out_sxt(s, 1, 2, args[0], args[1]);
1173 break;
1174 case INDEX_op_ext8u_i64:
1175 case INDEX_op_ext8u_i32:
1176 tcg_out_uxt(s, 0, args[0], args[1]);
1177 break;
1178 case INDEX_op_ext16u_i64:
1179 case INDEX_op_ext16u_i32:
1180 tcg_out_uxt(s, 1, args[0], args[1]);
1181 break;
1182 case INDEX_op_ext32u_i64:
1183 tcg_out_movr(s, 0, args[0], args[1]);
1184 break;
1186 default:
1187 tcg_abort(); /* opcode not implemented */
1191 static const TCGTargetOpDef aarch64_op_defs[] = {
1192 { INDEX_op_exit_tb, { } },
1193 { INDEX_op_goto_tb, { } },
1194 { INDEX_op_call, { "ri" } },
1195 { INDEX_op_br, { } },
1197 { INDEX_op_mov_i32, { "r", "r" } },
1198 { INDEX_op_mov_i64, { "r", "r" } },
1200 { INDEX_op_movi_i32, { "r" } },
1201 { INDEX_op_movi_i64, { "r" } },
1203 { INDEX_op_ld8u_i32, { "r", "r" } },
1204 { INDEX_op_ld8s_i32, { "r", "r" } },
1205 { INDEX_op_ld16u_i32, { "r", "r" } },
1206 { INDEX_op_ld16s_i32, { "r", "r" } },
1207 { INDEX_op_ld_i32, { "r", "r" } },
1208 { INDEX_op_ld8u_i64, { "r", "r" } },
1209 { INDEX_op_ld8s_i64, { "r", "r" } },
1210 { INDEX_op_ld16u_i64, { "r", "r" } },
1211 { INDEX_op_ld16s_i64, { "r", "r" } },
1212 { INDEX_op_ld32u_i64, { "r", "r" } },
1213 { INDEX_op_ld32s_i64, { "r", "r" } },
1214 { INDEX_op_ld_i64, { "r", "r" } },
1216 { INDEX_op_st8_i32, { "r", "r" } },
1217 { INDEX_op_st16_i32, { "r", "r" } },
1218 { INDEX_op_st_i32, { "r", "r" } },
1219 { INDEX_op_st8_i64, { "r", "r" } },
1220 { INDEX_op_st16_i64, { "r", "r" } },
1221 { INDEX_op_st32_i64, { "r", "r" } },
1222 { INDEX_op_st_i64, { "r", "r" } },
1224 { INDEX_op_add_i32, { "r", "r", "r" } },
1225 { INDEX_op_add_i64, { "r", "r", "r" } },
1226 { INDEX_op_sub_i32, { "r", "r", "r" } },
1227 { INDEX_op_sub_i64, { "r", "r", "r" } },
1228 { INDEX_op_mul_i32, { "r", "r", "r" } },
1229 { INDEX_op_mul_i64, { "r", "r", "r" } },
1230 { INDEX_op_and_i32, { "r", "r", "r" } },
1231 { INDEX_op_and_i64, { "r", "r", "r" } },
1232 { INDEX_op_or_i32, { "r", "r", "r" } },
1233 { INDEX_op_or_i64, { "r", "r", "r" } },
1234 { INDEX_op_xor_i32, { "r", "r", "r" } },
1235 { INDEX_op_xor_i64, { "r", "r", "r" } },
1237 { INDEX_op_shl_i32, { "r", "r", "ri" } },
1238 { INDEX_op_shr_i32, { "r", "r", "ri" } },
1239 { INDEX_op_sar_i32, { "r", "r", "ri" } },
1240 { INDEX_op_rotl_i32, { "r", "r", "ri" } },
1241 { INDEX_op_rotr_i32, { "r", "r", "ri" } },
1242 { INDEX_op_shl_i64, { "r", "r", "ri" } },
1243 { INDEX_op_shr_i64, { "r", "r", "ri" } },
1244 { INDEX_op_sar_i64, { "r", "r", "ri" } },
1245 { INDEX_op_rotl_i64, { "r", "r", "ri" } },
1246 { INDEX_op_rotr_i64, { "r", "r", "ri" } },
1248 { INDEX_op_brcond_i32, { "r", "r" } },
1249 { INDEX_op_setcond_i32, { "r", "r", "r" } },
1250 { INDEX_op_brcond_i64, { "r", "r" } },
1251 { INDEX_op_setcond_i64, { "r", "r", "r" } },
1253 { INDEX_op_qemu_ld8u, { "r", "l" } },
1254 { INDEX_op_qemu_ld8s, { "r", "l" } },
1255 { INDEX_op_qemu_ld16u, { "r", "l" } },
1256 { INDEX_op_qemu_ld16s, { "r", "l" } },
1257 { INDEX_op_qemu_ld32u, { "r", "l" } },
1258 { INDEX_op_qemu_ld32s, { "r", "l" } },
1260 { INDEX_op_qemu_ld32, { "r", "l" } },
1261 { INDEX_op_qemu_ld64, { "r", "l" } },
1263 { INDEX_op_qemu_st8, { "l", "l" } },
1264 { INDEX_op_qemu_st16, { "l", "l" } },
1265 { INDEX_op_qemu_st32, { "l", "l" } },
1266 { INDEX_op_qemu_st64, { "l", "l" } },
1268 { INDEX_op_bswap16_i32, { "r", "r" } },
1269 { INDEX_op_bswap32_i32, { "r", "r" } },
1270 { INDEX_op_bswap16_i64, { "r", "r" } },
1271 { INDEX_op_bswap32_i64, { "r", "r" } },
1272 { INDEX_op_bswap64_i64, { "r", "r" } },
1274 { INDEX_op_ext8s_i32, { "r", "r" } },
1275 { INDEX_op_ext16s_i32, { "r", "r" } },
1276 { INDEX_op_ext8u_i32, { "r", "r" } },
1277 { INDEX_op_ext16u_i32, { "r", "r" } },
1279 { INDEX_op_ext8s_i64, { "r", "r" } },
1280 { INDEX_op_ext16s_i64, { "r", "r" } },
1281 { INDEX_op_ext32s_i64, { "r", "r" } },
1282 { INDEX_op_ext8u_i64, { "r", "r" } },
1283 { INDEX_op_ext16u_i64, { "r", "r" } },
1284 { INDEX_op_ext32u_i64, { "r", "r" } },
1286 { -1 },
1289 static void tcg_target_init(TCGContext *s)
1291 #if !defined(CONFIG_USER_ONLY)
1292 /* fail safe */
1293 if ((1ULL << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) {
1294 tcg_abort();
1296 #endif
1297 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
1298 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
1300 tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1301 (1 << TCG_REG_X0) | (1 << TCG_REG_X1) |
1302 (1 << TCG_REG_X2) | (1 << TCG_REG_X3) |
1303 (1 << TCG_REG_X4) | (1 << TCG_REG_X5) |
1304 (1 << TCG_REG_X6) | (1 << TCG_REG_X7) |
1305 (1 << TCG_REG_X8) | (1 << TCG_REG_X9) |
1306 (1 << TCG_REG_X10) | (1 << TCG_REG_X11) |
1307 (1 << TCG_REG_X12) | (1 << TCG_REG_X13) |
1308 (1 << TCG_REG_X14) | (1 << TCG_REG_X15) |
1309 (1 << TCG_REG_X16) | (1 << TCG_REG_X17) |
1310 (1 << TCG_REG_X18));
1312 tcg_regset_clear(s->reserved_regs);
1313 tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
1314 tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP);
1315 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
1316 tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */
1318 tcg_add_target_add_op_defs(aarch64_op_defs);
1321 static inline void tcg_out_addi(TCGContext *s, int ext,
1322 TCGReg rd, TCGReg rn, unsigned int aimm)
1324 /* add immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */
1325 /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
1326 unsigned int base = ext ? 0x91000000 : 0x11000000;
1327 assert(aimm <= 0xfff);
1328 tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd);
1331 static inline void tcg_out_subi(TCGContext *s, int ext,
1332 TCGReg rd, TCGReg rn, unsigned int aimm)
1334 /* sub immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */
1335 /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
1336 unsigned int base = ext ? 0xd1000000 : 0x51000000;
1337 assert(aimm <= 0xfff);
1338 tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd);
1341 static void tcg_target_qemu_prologue(TCGContext *s)
1343 /* NB: frame sizes are in 16 byte stack units! */
1344 int frame_size_callee_saved, frame_size_tcg_locals;
1345 TCGReg r;
1347 /* save pairs (FP, LR) and (X19, X20) .. (X27, X28) */
1348 frame_size_callee_saved = (1) + (TCG_REG_X28 - TCG_REG_X19) / 2 + 1;
1350 /* frame size requirement for TCG local variables */
1351 frame_size_tcg_locals = TCG_STATIC_CALL_ARGS_SIZE
1352 + CPU_TEMP_BUF_NLONGS * sizeof(long)
1353 + (TCG_TARGET_STACK_ALIGN - 1);
1354 frame_size_tcg_locals &= ~(TCG_TARGET_STACK_ALIGN - 1);
1355 frame_size_tcg_locals /= TCG_TARGET_STACK_ALIGN;
1357 /* push (FP, LR) and update sp */
1358 tcg_out_push_pair(s, TCG_REG_SP,
1359 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1361 /* FP -> callee_saved */
1362 tcg_out_movr_sp(s, 1, TCG_REG_FP, TCG_REG_SP);
1364 /* store callee-preserved regs x19..x28 using FP -> callee_saved */
1365 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1366 int idx = (r - TCG_REG_X19) / 2 + 1;
1367 tcg_out_store_pair(s, TCG_REG_FP, r, r + 1, idx);
1370 /* make stack space for TCG locals */
1371 tcg_out_subi(s, 1, TCG_REG_SP, TCG_REG_SP,
1372 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1373 /* inform TCG about how to find TCG locals with register, offset, size */
1374 tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE,
1375 CPU_TEMP_BUF_NLONGS * sizeof(long));
1377 #if defined(CONFIG_USE_GUEST_BASE)
1378 if (GUEST_BASE) {
1379 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, GUEST_BASE);
1380 tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE);
1382 #endif
1384 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
1385 tcg_out_gotor(s, tcg_target_call_iarg_regs[1]);
1387 tb_ret_addr = s->code_ptr;
1389 /* remove TCG locals stack space */
1390 tcg_out_addi(s, 1, TCG_REG_SP, TCG_REG_SP,
1391 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1393 /* restore registers x19..x28.
1394 FP must be preserved, so it still points to callee_saved area */
1395 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1396 int idx = (r - TCG_REG_X19) / 2 + 1;
1397 tcg_out_load_pair(s, TCG_REG_FP, r, r + 1, idx);
1400 /* pop (FP, LR), restore SP to previous frame, return */
1401 tcg_out_pop_pair(s, TCG_REG_SP,
1402 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1403 tcg_out_ret(s);