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