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"
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 */
27 #ifdef TARGET_WORDS_BIGENDIAN
28 #define TCG_LDST_BSWAP 1
30 #define TCG_LDST_BSWAP 0
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] = {
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
64 # define TCG_REG_GUEST_BASE TCG_REG_XZR
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
)
96 case R_AARCH64_JUMP26
:
97 case R_AARCH64_CALL26
:
98 reloc_pc26(code_ptr
, value
);
100 case R_AARCH64_CONDBR19
:
101 reloc_pc19(code_ptr
, value
);
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
;
117 ct
->ct
|= TCG_CT_REG
;
118 tcg_regset_set32(ct
->u
.regs
, 0, (1ULL << TCG_TARGET_NB_REGS
) - 1);
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
);
141 static inline int tcg_target_const_match(tcg_target_long val
,
142 const TCGArgConstraint
*arg_ct
)
146 if (ct
& TCG_CT_CONST
) {
153 enum aarch64_cond_code
{
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 */
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
,
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 */
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
{
213 enum aarch64_srr_opc
{
220 static inline enum aarch64_ldst_op_data
221 aarch64_ldst_get_data(TCGOpcode 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
:
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
:
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
:
247 case INDEX_op_ld_i64
:
248 case INDEX_op_st_i64
:
256 static inline enum aarch64_ldst_op_type
257 aarch64_ldst_get_type(TCGOpcode 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
:
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
:
278 case INDEX_op_ld8s_i32
:
279 case INDEX_op_ld16s_i32
:
282 case INDEX_op_ld8s_i64
:
283 case INDEX_op_ld16s_i64
:
284 case INDEX_op_ld32s_i64
:
292 static inline uint32_t tcg_in32(TCGContext
*s
)
294 uint32_t v
= *(uint32_t *)s
->code_ptr
;
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
;
307 off
= (256 + offset
);
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. */
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
);
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
);
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
);
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
)
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
,
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
,
413 static inline void tcg_out_arith(TCGContext
*s
, enum aarch64_arith_opc opc
,
414 int ext
, TCGReg rd
, TCGReg rn
, TCGReg rm
,
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) {
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
)
475 bits
= ext
? 64 : 32;
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
)
505 bits
= ext
? 64 : 32;
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
,
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 */
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. */
545 insn
= (tcg_in32(s
) & 0x03ffffff) | 0x14000000;
549 static inline void tcg_out_goto_cond_noaddr(TCGContext
*s
, TCGCond c
)
551 /* see comments in tcg_out_goto_noaddr */
553 insn
= tcg_in32(s
) & (0x07ffff << 5);
554 insn
|= 0x54000000 | tcg_cond_to_aarch64
[c
];
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 */
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
);
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
)
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.
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 */
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
];
657 tcg_out_reloc(s
, s
->code_ptr
, R_AARCH64_JUMP26
, label_index
, 0);
658 tcg_out_goto_noaddr(s
);
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
];
670 tcg_out_reloc(s
, s
->code_ptr
, R_AARCH64_CONDBR19
, label_index
, 0);
671 tcg_out_goto_cond_noaddr(s
, c
);
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,
714 static const void * const qemu_ld_helpers
[4] = {
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] = {
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
)
737 tcg_out_ldst_r(s
, LDST_8
, LDST_LD
, data_r
, addr_r
, off_r
);
740 tcg_out_ldst_r(s
, LDST_8
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
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
);
754 tcg_out_ldst_r(s
, LDST_16
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
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
);
769 tcg_out_ldst_r(s
, LDST_32
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
783 static void tcg_out_qemu_st_direct(TCGContext
*s
, int opc
, TCGReg data_r
,
784 TCGReg addr_r
, TCGReg off_r
)
788 tcg_out_ldst_r(s
, LDST_8
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
795 tcg_out_ldst_r(s
, LDST_16
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
803 tcg_out_ldst_r(s
, LDST_32
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
811 tcg_out_ldst_r(s
, LDST_64
, LDST_ST
, data_r
, addr_r
, off_r
);
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
;
829 #ifdef CONFIG_SOFTMMU
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
);
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
;
864 #ifdef CONFIG_SOFTMMU
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]!
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. */
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
);
950 case INDEX_op_goto_tb
:
951 #ifndef USE_DIRECT_JUMP
952 #error "USE_DIRECT_JUMP required for aarch64"
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
;
964 tcg_out_call(s
, args
[0]);
966 tcg_out_callr(s
, args
[0]);
971 tcg_out_goto_label(s
, args
[0]);
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]);
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]);
1003 case INDEX_op_movi_i64
:
1004 tcg_out_movi(s
, TCG_TYPE_I64
, args
[0], args
[1]);
1006 case INDEX_op_movi_i32
:
1007 tcg_out_movi(s
, TCG_TYPE_I32
, args
[0], args
[1]);
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);
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);
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);
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);
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);
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]);
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]);
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]);
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]);
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]);
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]);
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
);
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]);
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]);
1113 case INDEX_op_qemu_ld8u
:
1114 tcg_out_qemu_ld(s
, args
, 0 | 0);
1116 case INDEX_op_qemu_ld8s
:
1117 tcg_out_qemu_ld(s
, args
, 4 | 0);
1119 case INDEX_op_qemu_ld16u
:
1120 tcg_out_qemu_ld(s
, args
, 0 | 1);
1122 case INDEX_op_qemu_ld16s
:
1123 tcg_out_qemu_ld(s
, args
, 4 | 1);
1125 case INDEX_op_qemu_ld32u
:
1126 tcg_out_qemu_ld(s
, args
, 0 | 2);
1128 case INDEX_op_qemu_ld32s
:
1129 tcg_out_qemu_ld(s
, args
, 4 | 2);
1131 case INDEX_op_qemu_ld32
:
1132 tcg_out_qemu_ld(s
, args
, 0 | 2);
1134 case INDEX_op_qemu_ld64
:
1135 tcg_out_qemu_ld(s
, args
, 0 | 3);
1137 case INDEX_op_qemu_st8
:
1138 tcg_out_qemu_st(s
, args
, 0);
1140 case INDEX_op_qemu_st16
:
1141 tcg_out_qemu_st(s
, args
, 1);
1143 case INDEX_op_qemu_st32
:
1144 tcg_out_qemu_st(s
, args
, 2);
1146 case INDEX_op_qemu_st64
:
1147 tcg_out_qemu_st(s
, args
, 3);
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]);
1156 case INDEX_op_bswap16_i64
:
1157 case INDEX_op_bswap16_i32
:
1158 tcg_out_rev16(s
, 0, args
[0], args
[1]);
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]);
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]);
1171 case INDEX_op_ext32s_i64
:
1172 tcg_out_sxt(s
, 1, 2, args
[0], args
[1]);
1174 case INDEX_op_ext8u_i64
:
1175 case INDEX_op_ext8u_i32
:
1176 tcg_out_uxt(s
, 0, args
[0], args
[1]);
1178 case INDEX_op_ext16u_i64
:
1179 case INDEX_op_ext16u_i32
:
1180 tcg_out_uxt(s
, 1, args
[0], args
[1]);
1182 case INDEX_op_ext32u_i64
:
1183 tcg_out_movr(s
, 0, args
[0], args
[1]);
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" } },
1289 static void tcg_target_init(TCGContext
*s
)
1291 #if !defined(CONFIG_USER_ONLY)
1293 if ((1ULL << CPU_TLB_ENTRY_BITS
) != sizeof(CPUTLBEntry
)) {
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
;
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)
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
);
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
);