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