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"
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 */
28 #ifdef TARGET_WORDS_BIGENDIAN
29 #define TCG_LDST_BSWAP 1
31 #define TCG_LDST_BSWAP 0
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] = {
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
65 # define TCG_REG_GUEST_BASE TCG_REG_XZR
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
)
97 case R_AARCH64_JUMP26
:
98 case R_AARCH64_CALL26
:
99 reloc_pc26(code_ptr
, value
);
101 case R_AARCH64_CONDBR19
:
102 reloc_pc19(code_ptr
, value
);
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
;
118 ct
->ct
|= TCG_CT_REG
;
119 tcg_regset_set32(ct
->u
.regs
, 0, (1ULL << TCG_TARGET_NB_REGS
) - 1);
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
);
142 static inline int tcg_target_const_match(tcg_target_long val
,
143 const TCGArgConstraint
*arg_ct
)
147 if (ct
& TCG_CT_CONST
) {
154 enum aarch64_cond_code
{
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 */
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
,
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 */
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
{
214 enum aarch64_srr_opc
{
221 static inline enum aarch64_ldst_op_data
222 aarch64_ldst_get_data(TCGOpcode 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
:
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
:
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
:
248 case INDEX_op_ld_i64
:
249 case INDEX_op_st_i64
:
257 static inline enum aarch64_ldst_op_type
258 aarch64_ldst_get_type(TCGOpcode 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
:
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
:
279 case INDEX_op_ld8s_i32
:
280 case INDEX_op_ld16s_i32
:
283 case INDEX_op_ld8s_i64
:
284 case INDEX_op_ld16s_i64
:
285 case INDEX_op_ld32s_i64
:
293 static inline uint32_t tcg_in32(TCGContext
*s
)
295 uint32_t v
= *(uint32_t *)s
->code_ptr
;
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
;
308 off
= (256 + offset
);
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. */
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
);
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
);
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
);
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
);
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
)
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
,
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
,
440 static inline void tcg_out_arith(TCGContext
*s
, enum aarch64_arith_opc opc
,
441 int ext
, TCGReg rd
, TCGReg rn
, TCGReg rm
,
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) {
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
)
502 bits
= ext
? 64 : 32;
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
)
532 bits
= ext
? 64 : 32;
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
,
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 */
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. */
572 insn
= (tcg_in32(s
) & 0x03ffffff) | 0x14000000;
576 static inline void tcg_out_goto_cond_noaddr(TCGContext
*s
, TCGCond c
)
578 /* see comments in tcg_out_goto_noaddr */
580 insn
= tcg_in32(s
) & (0x07ffff << 5);
581 insn
|= 0x54000000 | tcg_cond_to_aarch64
[c
];
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 */
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
);
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
)
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.
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 */
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
];
684 tcg_out_reloc(s
, s
->code_ptr
, R_AARCH64_JUMP26
, label_index
, 0);
685 tcg_out_goto_noaddr(s
);
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
];
697 tcg_out_reloc(s
, s
->code_ptr
, R_AARCH64_CONDBR19
, label_index
, 0);
698 tcg_out_goto_cond_noaddr(s
, c
);
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;
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 */
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;
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 */
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] = {
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] = {
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
);
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
);
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
,
841 uint8_t *raddr
, uint8_t *label_ptr
)
843 TCGLabelQemuLdst
*label
= new_ldst_label(s
);
845 label
->is_ld
= is_ld
;
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.
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
)
909 tcg_out_ldst_r(s
, LDST_8
, LDST_LD
, data_r
, addr_r
, off_r
);
912 tcg_out_ldst_r(s
, LDST_8
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
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
);
926 tcg_out_ldst_r(s
, LDST_16
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
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
);
941 tcg_out_ldst_r(s
, LDST_32
, LDST_LD_S_X
, data_r
, addr_r
, off_r
);
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
);
955 static void tcg_out_qemu_st_direct(TCGContext
*s
, int opc
, TCGReg data_r
,
956 TCGReg addr_r
, TCGReg off_r
)
960 tcg_out_ldst_r(s
, LDST_8
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
967 tcg_out_ldst_r(s
, LDST_16
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
975 tcg_out_ldst_r(s
, LDST_32
, LDST_ST
, data_r
, addr_r
, off_r
);
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
);
983 tcg_out_ldst_r(s
, LDST_64
, LDST_ST
, data_r
, addr_r
, off_r
);
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
;
1001 #ifdef CONFIG_SOFTMMU
1002 mem_index
= args
[2];
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
;
1024 #ifdef CONFIG_SOFTMMU
1025 mem_index
= args
[2];
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]!
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. */
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
);
1103 case INDEX_op_goto_tb
:
1104 #ifndef USE_DIRECT_JUMP
1105 #error "USE_DIRECT_JUMP required for aarch64"
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
;
1116 if (const_args
[0]) {
1117 tcg_out_call(s
, args
[0]);
1119 tcg_out_callr(s
, args
[0]);
1124 tcg_out_goto_label(s
, args
[0]);
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]);
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]);
1156 case INDEX_op_movi_i64
:
1157 tcg_out_movi(s
, TCG_TYPE_I64
, args
[0], args
[1]);
1159 case INDEX_op_movi_i32
:
1160 tcg_out_movi(s
, TCG_TYPE_I32
, args
[0], args
[1]);
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);
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);
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);
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);
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);
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]);
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]);
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]);
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]);
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]);
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]);
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
);
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]);
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]);
1266 case INDEX_op_qemu_ld8u
:
1267 tcg_out_qemu_ld(s
, args
, 0 | 0);
1269 case INDEX_op_qemu_ld8s
:
1270 tcg_out_qemu_ld(s
, args
, 4 | 0);
1272 case INDEX_op_qemu_ld16u
:
1273 tcg_out_qemu_ld(s
, args
, 0 | 1);
1275 case INDEX_op_qemu_ld16s
:
1276 tcg_out_qemu_ld(s
, args
, 4 | 1);
1278 case INDEX_op_qemu_ld32u
:
1279 tcg_out_qemu_ld(s
, args
, 0 | 2);
1281 case INDEX_op_qemu_ld32s
:
1282 tcg_out_qemu_ld(s
, args
, 4 | 2);
1284 case INDEX_op_qemu_ld32
:
1285 tcg_out_qemu_ld(s
, args
, 0 | 2);
1287 case INDEX_op_qemu_ld64
:
1288 tcg_out_qemu_ld(s
, args
, 0 | 3);
1290 case INDEX_op_qemu_st8
:
1291 tcg_out_qemu_st(s
, args
, 0);
1293 case INDEX_op_qemu_st16
:
1294 tcg_out_qemu_st(s
, args
, 1);
1296 case INDEX_op_qemu_st32
:
1297 tcg_out_qemu_st(s
, args
, 2);
1299 case INDEX_op_qemu_st64
:
1300 tcg_out_qemu_st(s
, args
, 3);
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]);
1309 case INDEX_op_bswap16_i64
:
1310 case INDEX_op_bswap16_i32
:
1311 tcg_out_rev16(s
, 0, args
[0], args
[1]);
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]);
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]);
1324 case INDEX_op_ext32s_i64
:
1325 tcg_out_sxt(s
, 1, 2, args
[0], args
[1]);
1327 case INDEX_op_ext8u_i64
:
1328 case INDEX_op_ext8u_i32
:
1329 tcg_out_uxt(s
, 0, args
[0], args
[1]);
1331 case INDEX_op_ext16u_i64
:
1332 case INDEX_op_ext16u_i32
:
1333 tcg_out_uxt(s
, 1, args
[0], args
[1]);
1335 case INDEX_op_ext32u_i64
:
1336 tcg_out_movr(s
, 0, args
[0], args
[1]);
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" } },
1442 static void tcg_target_init(TCGContext
*s
)
1444 #if !defined(CONFIG_USER_ONLY)
1446 if ((1ULL << CPU_TLB_ENTRY_BITS
) != sizeof(CPUTLBEntry
)) {
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
;
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)
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
);
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
);