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