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