tcg/aarch64: implement AND/TEST immediate pattern
[qemu.git] / tcg / aarch64 / tcg-target.c
blobbb59794046692292cb2c8c35c0ec6d990aba7b11
1 /*
2 * Initial TCG Implementation for aarch64
4 * Copyright (c) 2013 Huawei Technologies Duesseldorf GmbH
5 * Written by Claudio Fontana
7 * This work is licensed under the terms of the GNU GPL, version 2 or
8 * (at your option) any later version.
10 * See the COPYING file in the top-level directory for details.
13 #include "qemu/bitops.h"
15 #ifndef NDEBUG
16 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
17 "%x0", "%x1", "%x2", "%x3", "%x4", "%x5", "%x6", "%x7",
18 "%x8", "%x9", "%x10", "%x11", "%x12", "%x13", "%x14", "%x15",
19 "%x16", "%x17", "%x18", "%x19", "%x20", "%x21", "%x22", "%x23",
20 "%x24", "%x25", "%x26", "%x27", "%x28",
21 "%fp", /* frame pointer */
22 "%lr", /* link register */
23 "%sp", /* stack pointer */
25 #endif /* NDEBUG */
27 static 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,
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,
36 TCG_REG_X18, TCG_REG_X19, /* will not use these, see tcg_target_init */
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,
41 TCG_REG_X8, /* will not use, see tcg_target_init */
44 static 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
48 static const int tcg_target_call_oarg_regs[1] = {
49 TCG_REG_X0
52 #define TCG_REG_TMP TCG_REG_X8
54 static inline void reloc_pc26(void *code_ptr, tcg_target_long target)
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;
65 static inline void reloc_pc19(void *code_ptr, tcg_target_long target)
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;
76 static inline void patch_reloc(uint8_t *code_ptr, int type,
77 tcg_target_long value, tcg_target_long addend)
79 value += addend;
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;
90 default:
91 tcg_abort();
95 /* parse target specific constraints */
96 static int target_parse_constraint(TCGArgConstraint *ct,
97 const char **pct_str)
99 const char *ct_str = *pct_str;
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;
122 ct_str++;
123 *pct_str = ct_str;
124 return 0;
127 static inline int tcg_target_const_match(tcg_target_long val,
128 const TCGArgConstraint *arg_ct)
130 int ct = arg_ct->ct;
132 if (ct & TCG_CT_CONST) {
133 return 1;
136 return 0;
139 enum 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 */
160 static 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,
174 /* opcodes for LDR / STR instructions with base + simm9 addressing */
175 enum 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,
181 enum 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 */
188 enum aarch64_arith_opc {
189 ARITH_AND = 0x0a,
190 ARITH_ADD = 0x0b,
191 ARITH_OR = 0x2a,
192 ARITH_ADDS = 0x2b,
193 ARITH_XOR = 0x4a,
194 ARITH_SUB = 0x4b,
195 ARITH_ANDS = 0x6a,
196 ARITH_SUBS = 0x6b,
199 enum aarch64_srr_opc {
200 SRR_SHL = 0x0,
201 SRR_SHR = 0x4,
202 SRR_SAR = 0x8,
203 SRR_ROR = 0xc
206 static inline enum aarch64_ldst_op_data
207 aarch64_ldst_get_data(TCGOpcode tcg_op)
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;
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;
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;
233 case INDEX_op_ld_i64:
234 case INDEX_op_st_i64:
235 return LDST_64;
237 default:
238 tcg_abort();
242 static inline enum aarch64_ldst_op_type
243 aarch64_ldst_get_type(TCGOpcode tcg_op)
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;
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;
264 case INDEX_op_ld8s_i32:
265 case INDEX_op_ld16s_i32:
266 return LDST_LD_S_W;
268 case INDEX_op_ld8s_i64:
269 case INDEX_op_ld16s_i64:
270 case INDEX_op_ld32s_i64:
271 return LDST_LD_S_X;
273 default:
274 tcg_abort();
278 static inline uint32_t tcg_in32(TCGContext *s)
280 uint32_t v = *(uint32_t *)s->code_ptr;
281 return v;
284 static 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)
289 /* use LDUR with BASE register with 9bit signed unscaled offset */
290 unsigned int mod, off;
292 if (offset < 0) {
293 off = (256 + offset);
294 mod = 0x1;
295 } else {
296 off = offset;
297 mod = 0x0;
300 mod |= op_type;
301 tcg_out32(s, op_data << 24 | mod << 20 | off << 12 | rn << 5 | rd);
304 static inline void tcg_out_movr(TCGContext *s, int ext, TCGReg rd, TCGReg src)
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);
312 static inline void tcg_out_movi_aux(TCGContext *s,
313 TCGReg rd, uint64_t value)
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);
334 static inline void tcg_out_movi(TCGContext *s, TCGType type,
335 TCGReg rd, tcg_target_long value)
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);
344 static 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)
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);
356 /* solve the whole ldst problem */
357 static 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)
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);
369 /* mov alias implemented with add immediate, useful to move to/from SP */
370 static inline void tcg_out_movr_sp(TCGContext *s, int ext, TCGReg rd, TCGReg rn)
372 /* using ADD 0x11000000 | (ext) | rn << 5 | rd */
373 unsigned int base = ext ? 0x91000000 : 0x11000000;
374 tcg_out32(s, base | rn << 5 | rd);
377 static inline void tcg_out_mov(TCGContext *s,
378 TCGType type, TCGReg ret, TCGReg arg)
380 if (ret != arg) {
381 tcg_out_movr(s, type == TCG_TYPE_I64, ret, arg);
385 static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
386 TCGReg arg1, tcg_target_long arg2)
388 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_LD,
389 arg, arg1, arg2);
392 static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
393 TCGReg arg1, tcg_target_long arg2)
395 tcg_out_ldst(s, (type == TCG_TYPE_I64) ? LDST_64 : LDST_32, LDST_ST,
396 arg, arg1, arg2);
399 static inline void tcg_out_arith(TCGContext *s, enum aarch64_arith_opc opc,
400 int ext, TCGReg rd, TCGReg rn, TCGReg rm,
401 int shift_imm)
403 /* Using shifted register arithmetic operations */
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;
413 tcg_out32(s, base | rm << 16 | shift | rn << 5 | rd);
416 static inline void tcg_out_mul(TCGContext *s, int ext,
417 TCGReg rd, TCGReg rn, TCGReg rm)
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);
424 static inline void tcg_out_shiftrot_reg(TCGContext *s,
425 enum aarch64_srr_opc opc, int ext,
426 TCGReg rd, TCGReg rn, TCGReg rm)
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);
433 static inline void tcg_out_ubfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
434 unsigned int a, unsigned int b)
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);
441 static inline void tcg_out_sbfm(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
442 unsigned int a, unsigned int b)
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);
449 static inline void tcg_out_extr(TCGContext *s, int ext, TCGReg rd,
450 TCGReg rn, TCGReg rm, unsigned int a)
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);
457 static inline void tcg_out_shl(TCGContext *s, int ext,
458 TCGReg rd, TCGReg rn, unsigned int m)
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));
466 static inline void tcg_out_shr(TCGContext *s, int ext,
467 TCGReg rd, TCGReg rn, unsigned int m)
469 int max = ext ? 63 : 31;
470 tcg_out_ubfm(s, ext, rd, rn, m & max, max);
473 static inline void tcg_out_sar(TCGContext *s, int ext,
474 TCGReg rd, TCGReg rn, unsigned int m)
476 int max = ext ? 63 : 31;
477 tcg_out_sbfm(s, ext, rd, rn, m & max, max);
480 static inline void tcg_out_rotr(TCGContext *s, int ext,
481 TCGReg rd, TCGReg rn, unsigned int m)
483 int max = ext ? 63 : 31;
484 tcg_out_extr(s, ext, rd, rn, rn, m & max);
487 static inline void tcg_out_rotl(TCGContext *s, int ext,
488 TCGReg rd, TCGReg rn, unsigned int m)
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));
496 static inline void tcg_out_cmp(TCGContext *s, int ext, TCGReg rn, TCGReg rm,
497 int shift_imm)
499 /* Using CMP alias SUBS wzr, Wn, Wm */
500 tcg_out_arith(s, ARITH_SUBS, ext, TCG_REG_XZR, rn, rm, shift_imm);
503 static inline void tcg_out_cset(TCGContext *s, int ext, TCGReg rd, TCGCond c)
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);
510 static inline void tcg_out_goto(TCGContext *s, tcg_target_long target)
512 tcg_target_long offset;
513 offset = (target - (tcg_target_long)s->code_ptr) / 4;
515 if (offset < -0x02000000 || offset >= 0x02000000) {
516 /* out of 26bit range */
517 tcg_abort();
520 tcg_out32(s, 0x14000000 | (offset & 0x03ffffff));
523 static inline void tcg_out_goto_noaddr(TCGContext *s)
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);
535 static inline void tcg_out_goto_cond_noaddr(TCGContext *s, TCGCond c)
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);
544 static inline void tcg_out_goto_cond(TCGContext *s, TCGCond c,
545 tcg_target_long target)
547 tcg_target_long offset;
548 offset = (target - (tcg_target_long)s->code_ptr) / 4;
550 if (offset < -0x40000 || offset >= 0x40000) {
551 /* out of 19bit range */
552 tcg_abort();
555 offset &= 0x7ffff;
556 tcg_out32(s, 0x54000000 | tcg_cond_to_aarch64[c] | offset << 5);
559 static inline void tcg_out_callr(TCGContext *s, TCGReg reg)
561 tcg_out32(s, 0xd63f0000 | reg << 5);
564 static inline void tcg_out_gotor(TCGContext *s, TCGReg reg)
566 tcg_out32(s, 0xd61f0000 | reg << 5);
569 static inline void tcg_out_call(TCGContext *s, tcg_target_long target)
571 tcg_target_long offset;
573 offset = (target - (tcg_target_long)s->code_ptr) / 4;
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));
583 /* encode a logical immediate, mapping user parameter
584 M=set bits pattern length to S=M-1 */
585 static inline unsigned int
586 aarch64_limm(unsigned int m, unsigned int r)
588 assert(m > 0);
589 return r << 16 | (m - 1) << 10;
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.
600 static inline void tcg_out_tst(TCGContext *s, int ext, TCGReg rn,
601 unsigned int m, unsigned int r)
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);
608 /* and a register with a bit pattern, similarly to TST, no flags change */
609 static inline void tcg_out_andi(TCGContext *s, int ext, TCGReg rd, TCGReg rn,
610 unsigned int m, unsigned int r)
612 /* using AND 0x12000000 */
613 unsigned int base = ext ? 0x92400000 : 0x12000000;
614 tcg_out32(s, base | aarch64_limm(m, r) | rn << 5 | rd);
617 static inline void tcg_out_ret(TCGContext *s)
619 /* emit RET { LR } */
620 tcg_out32(s, 0xd65f03c0);
623 void aarch64_tb_set_jmp_target(uintptr_t jmp_addr, uintptr_t addr)
625 tcg_target_long target, offset;
626 target = (tcg_target_long)addr;
627 offset = (target - (tcg_target_long)jmp_addr) / 4;
629 if (offset < -0x02000000 || offset >= 0x02000000) {
630 /* out of 26bit range */
631 tcg_abort();
634 patch_reloc((uint8_t *)jmp_addr, R_AARCH64_JUMP26, target, 0);
635 flush_icache_range(jmp_addr, jmp_addr + 4);
638 static inline void tcg_out_goto_label(TCGContext *s, int label_index)
640 TCGLabel *l = &s->labels[label_index];
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);
650 static inline void tcg_out_goto_label_cond(TCGContext *s,
651 TCGCond c, int label_index)
653 TCGLabel *l = &s->labels[label_index];
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);
663 #ifdef CONFIG_SOFTMMU
664 #include "exec/softmmu_defs.h"
666 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
667 int mmu_idx) */
668 static const void * const qemu_ld_helpers[4] = {
669 helper_ldb_mmu,
670 helper_ldw_mmu,
671 helper_ldl_mmu,
672 helper_ldq_mmu,
675 /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
676 uintxx_t val, int mmu_idx) */
677 static const void * const qemu_st_helpers[4] = {
678 helper_stb_mmu,
679 helper_stw_mmu,
680 helper_stl_mmu,
681 helper_stq_mmu,
684 #endif /* CONFIG_SOFTMMU */
686 static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
688 TCGReg addr_reg, data_reg;
689 #ifdef CONFIG_SOFTMMU
690 int mem_index, s_bits;
691 #endif
692 data_reg = args[0];
693 addr_reg = args[1];
695 #ifdef CONFIG_SOFTMMU
696 mem_index = args[2];
697 s_bits = opc & 3;
699 /* TODO: insert TLB lookup here */
701 /* all arguments passed via registers */
702 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
703 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg);
704 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X2, mem_index);
705 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
706 (tcg_target_long)qemu_ld_helpers[s_bits]);
707 tcg_out_callr(s, TCG_REG_TMP);
709 if (opc & 0x04) { /* sign extend */
710 unsigned int bits = 8 * (1 << s_bits) - 1;
711 tcg_out_sbfm(s, 1, data_reg, TCG_REG_X0, 0, bits); /* 7|15|31 */
712 } else {
713 tcg_out_movr(s, 1, data_reg, TCG_REG_X0);
716 #else /* !CONFIG_SOFTMMU */
717 tcg_abort(); /* TODO */
718 #endif
721 static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
723 TCGReg addr_reg, data_reg;
724 #ifdef CONFIG_SOFTMMU
725 int mem_index, s_bits;
726 #endif
727 data_reg = args[0];
728 addr_reg = args[1];
730 #ifdef CONFIG_SOFTMMU
731 mem_index = args[2];
732 s_bits = opc & 3;
734 /* TODO: insert TLB lookup here */
736 /* all arguments passed via registers */
737 tcg_out_movr(s, 1, TCG_REG_X0, TCG_AREG0);
738 tcg_out_movr(s, (TARGET_LONG_BITS == 64), TCG_REG_X1, addr_reg);
739 tcg_out_movr(s, 1, TCG_REG_X2, data_reg);
740 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_X3, mem_index);
741 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP,
742 (tcg_target_long)qemu_st_helpers[s_bits]);
743 tcg_out_callr(s, TCG_REG_TMP);
745 #else /* !CONFIG_SOFTMMU */
746 tcg_abort(); /* TODO */
747 #endif
750 static uint8_t *tb_ret_addr;
752 /* callee stack use example:
753 stp x29, x30, [sp,#-32]!
754 mov x29, sp
755 stp x1, x2, [sp,#16]
757 ldp x1, x2, [sp,#16]
758 ldp x29, x30, [sp],#32
762 /* push r1 and r2, and alloc stack space for a total of
763 alloc_n elements (1 element=16 bytes, must be between 1 and 31. */
764 static inline void tcg_out_push_pair(TCGContext *s, TCGReg addr,
765 TCGReg r1, TCGReg r2, int alloc_n)
767 /* using indexed scaled simm7 STP 0x28800000 | (ext) | 0x01000000 (pre-idx)
768 | alloc_n * (-1) << 16 | r2 << 10 | addr << 5 | r1 */
769 assert(alloc_n > 0 && alloc_n < 0x20);
770 alloc_n = (-alloc_n) & 0x3f;
771 tcg_out32(s, 0xa9800000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
774 /* dealloc stack space for a total of alloc_n elements and pop r1, r2. */
775 static inline void tcg_out_pop_pair(TCGContext *s, TCGReg addr,
776 TCGReg r1, TCGReg r2, int alloc_n)
778 /* using indexed scaled simm7 LDP 0x28c00000 | (ext) | nothing (post-idx)
779 | alloc_n << 16 | r2 << 10 | addr << 5 | r1 */
780 assert(alloc_n > 0 && alloc_n < 0x20);
781 tcg_out32(s, 0xa8c00000 | alloc_n << 16 | r2 << 10 | addr << 5 | r1);
784 static inline void tcg_out_store_pair(TCGContext *s, TCGReg addr,
785 TCGReg r1, TCGReg r2, int idx)
787 /* using register pair offset simm7 STP 0x29000000 | (ext)
788 | idx << 16 | r2 << 10 | addr << 5 | r1 */
789 assert(idx > 0 && idx < 0x20);
790 tcg_out32(s, 0xa9000000 | idx << 16 | r2 << 10 | addr << 5 | r1);
793 static inline void tcg_out_load_pair(TCGContext *s, TCGReg addr,
794 TCGReg r1, TCGReg r2, int idx)
796 /* using register pair offset simm7 LDP 0x29400000 | (ext)
797 | idx << 16 | r2 << 10 | addr << 5 | r1 */
798 assert(idx > 0 && idx < 0x20);
799 tcg_out32(s, 0xa9400000 | idx << 16 | r2 << 10 | addr << 5 | r1);
802 static void tcg_out_op(TCGContext *s, TCGOpcode opc,
803 const TCGArg *args, const int *const_args)
805 /* ext will be set in the switch below, which will fall through to the
806 common code. It triggers the use of extended regs where appropriate. */
807 int ext = 0;
809 switch (opc) {
810 case INDEX_op_exit_tb:
811 tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X0, args[0]);
812 tcg_out_goto(s, (tcg_target_long)tb_ret_addr);
813 break;
815 case INDEX_op_goto_tb:
816 #ifndef USE_DIRECT_JUMP
817 #error "USE_DIRECT_JUMP required for aarch64"
818 #endif
819 assert(s->tb_jmp_offset != NULL); /* consistency for USE_DIRECT_JUMP */
820 s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
821 /* actual branch destination will be patched by
822 aarch64_tb_set_jmp_target later, beware retranslation. */
823 tcg_out_goto_noaddr(s);
824 s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
825 break;
827 case INDEX_op_call:
828 if (const_args[0]) {
829 tcg_out_call(s, args[0]);
830 } else {
831 tcg_out_callr(s, args[0]);
833 break;
835 case INDEX_op_br:
836 tcg_out_goto_label(s, args[0]);
837 break;
839 case INDEX_op_ld_i32:
840 case INDEX_op_ld_i64:
841 case INDEX_op_st_i32:
842 case INDEX_op_st_i64:
843 case INDEX_op_ld8u_i32:
844 case INDEX_op_ld8s_i32:
845 case INDEX_op_ld16u_i32:
846 case INDEX_op_ld16s_i32:
847 case INDEX_op_ld8u_i64:
848 case INDEX_op_ld8s_i64:
849 case INDEX_op_ld16u_i64:
850 case INDEX_op_ld16s_i64:
851 case INDEX_op_ld32u_i64:
852 case INDEX_op_ld32s_i64:
853 case INDEX_op_st8_i32:
854 case INDEX_op_st8_i64:
855 case INDEX_op_st16_i32:
856 case INDEX_op_st16_i64:
857 case INDEX_op_st32_i64:
858 tcg_out_ldst(s, aarch64_ldst_get_data(opc), aarch64_ldst_get_type(opc),
859 args[0], args[1], args[2]);
860 break;
862 case INDEX_op_mov_i64:
863 ext = 1; /* fall through */
864 case INDEX_op_mov_i32:
865 tcg_out_movr(s, ext, args[0], args[1]);
866 break;
868 case INDEX_op_movi_i64:
869 tcg_out_movi(s, TCG_TYPE_I64, args[0], args[1]);
870 break;
871 case INDEX_op_movi_i32:
872 tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
873 break;
875 case INDEX_op_add_i64:
876 ext = 1; /* fall through */
877 case INDEX_op_add_i32:
878 tcg_out_arith(s, ARITH_ADD, ext, args[0], args[1], args[2], 0);
879 break;
881 case INDEX_op_sub_i64:
882 ext = 1; /* fall through */
883 case INDEX_op_sub_i32:
884 tcg_out_arith(s, ARITH_SUB, ext, args[0], args[1], args[2], 0);
885 break;
887 case INDEX_op_and_i64:
888 ext = 1; /* fall through */
889 case INDEX_op_and_i32:
890 tcg_out_arith(s, ARITH_AND, ext, args[0], args[1], args[2], 0);
891 break;
893 case INDEX_op_or_i64:
894 ext = 1; /* fall through */
895 case INDEX_op_or_i32:
896 tcg_out_arith(s, ARITH_OR, ext, args[0], args[1], args[2], 0);
897 break;
899 case INDEX_op_xor_i64:
900 ext = 1; /* fall through */
901 case INDEX_op_xor_i32:
902 tcg_out_arith(s, ARITH_XOR, ext, args[0], args[1], args[2], 0);
903 break;
905 case INDEX_op_mul_i64:
906 ext = 1; /* fall through */
907 case INDEX_op_mul_i32:
908 tcg_out_mul(s, ext, args[0], args[1], args[2]);
909 break;
911 case INDEX_op_shl_i64:
912 ext = 1; /* fall through */
913 case INDEX_op_shl_i32:
914 if (const_args[2]) { /* LSL / UBFM Wd, Wn, (32 - m) */
915 tcg_out_shl(s, ext, args[0], args[1], args[2]);
916 } else { /* LSL / LSLV */
917 tcg_out_shiftrot_reg(s, SRR_SHL, ext, args[0], args[1], args[2]);
919 break;
921 case INDEX_op_shr_i64:
922 ext = 1; /* fall through */
923 case INDEX_op_shr_i32:
924 if (const_args[2]) { /* LSR / UBFM Wd, Wn, m, 31 */
925 tcg_out_shr(s, ext, args[0], args[1], args[2]);
926 } else { /* LSR / LSRV */
927 tcg_out_shiftrot_reg(s, SRR_SHR, ext, args[0], args[1], args[2]);
929 break;
931 case INDEX_op_sar_i64:
932 ext = 1; /* fall through */
933 case INDEX_op_sar_i32:
934 if (const_args[2]) { /* ASR / SBFM Wd, Wn, m, 31 */
935 tcg_out_sar(s, ext, args[0], args[1], args[2]);
936 } else { /* ASR / ASRV */
937 tcg_out_shiftrot_reg(s, SRR_SAR, ext, args[0], args[1], args[2]);
939 break;
941 case INDEX_op_rotr_i64:
942 ext = 1; /* fall through */
943 case INDEX_op_rotr_i32:
944 if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, m */
945 tcg_out_rotr(s, ext, args[0], args[1], args[2]);
946 } else { /* ROR / RORV */
947 tcg_out_shiftrot_reg(s, SRR_ROR, ext, args[0], args[1], args[2]);
949 break;
951 case INDEX_op_rotl_i64:
952 ext = 1; /* fall through */
953 case INDEX_op_rotl_i32: /* same as rotate right by (32 - m) */
954 if (const_args[2]) { /* ROR / EXTR Wd, Wm, Wm, 32 - m */
955 tcg_out_rotl(s, ext, args[0], args[1], args[2]);
956 } else {
957 tcg_out_arith(s, ARITH_SUB, 0,
958 TCG_REG_TMP, TCG_REG_XZR, args[2], 0);
959 tcg_out_shiftrot_reg(s, SRR_ROR, ext,
960 args[0], args[1], TCG_REG_TMP);
962 break;
964 case INDEX_op_brcond_i64:
965 ext = 1; /* fall through */
966 case INDEX_op_brcond_i32: /* CMP 0, 1, cond(2), label 3 */
967 tcg_out_cmp(s, ext, args[0], args[1], 0);
968 tcg_out_goto_label_cond(s, args[2], args[3]);
969 break;
971 case INDEX_op_setcond_i64:
972 ext = 1; /* fall through */
973 case INDEX_op_setcond_i32:
974 tcg_out_cmp(s, ext, args[1], args[2], 0);
975 tcg_out_cset(s, 0, args[0], args[3]);
976 break;
978 case INDEX_op_qemu_ld8u:
979 tcg_out_qemu_ld(s, args, 0 | 0);
980 break;
981 case INDEX_op_qemu_ld8s:
982 tcg_out_qemu_ld(s, args, 4 | 0);
983 break;
984 case INDEX_op_qemu_ld16u:
985 tcg_out_qemu_ld(s, args, 0 | 1);
986 break;
987 case INDEX_op_qemu_ld16s:
988 tcg_out_qemu_ld(s, args, 4 | 1);
989 break;
990 case INDEX_op_qemu_ld32u:
991 tcg_out_qemu_ld(s, args, 0 | 2);
992 break;
993 case INDEX_op_qemu_ld32s:
994 tcg_out_qemu_ld(s, args, 4 | 2);
995 break;
996 case INDEX_op_qemu_ld32:
997 tcg_out_qemu_ld(s, args, 0 | 2);
998 break;
999 case INDEX_op_qemu_ld64:
1000 tcg_out_qemu_ld(s, args, 0 | 3);
1001 break;
1002 case INDEX_op_qemu_st8:
1003 tcg_out_qemu_st(s, args, 0);
1004 break;
1005 case INDEX_op_qemu_st16:
1006 tcg_out_qemu_st(s, args, 1);
1007 break;
1008 case INDEX_op_qemu_st32:
1009 tcg_out_qemu_st(s, args, 2);
1010 break;
1011 case INDEX_op_qemu_st64:
1012 tcg_out_qemu_st(s, args, 3);
1013 break;
1015 default:
1016 tcg_abort(); /* opcode not implemented */
1020 static const TCGTargetOpDef aarch64_op_defs[] = {
1021 { INDEX_op_exit_tb, { } },
1022 { INDEX_op_goto_tb, { } },
1023 { INDEX_op_call, { "ri" } },
1024 { INDEX_op_br, { } },
1026 { INDEX_op_mov_i32, { "r", "r" } },
1027 { INDEX_op_mov_i64, { "r", "r" } },
1029 { INDEX_op_movi_i32, { "r" } },
1030 { INDEX_op_movi_i64, { "r" } },
1032 { INDEX_op_ld8u_i32, { "r", "r" } },
1033 { INDEX_op_ld8s_i32, { "r", "r" } },
1034 { INDEX_op_ld16u_i32, { "r", "r" } },
1035 { INDEX_op_ld16s_i32, { "r", "r" } },
1036 { INDEX_op_ld_i32, { "r", "r" } },
1037 { INDEX_op_ld8u_i64, { "r", "r" } },
1038 { INDEX_op_ld8s_i64, { "r", "r" } },
1039 { INDEX_op_ld16u_i64, { "r", "r" } },
1040 { INDEX_op_ld16s_i64, { "r", "r" } },
1041 { INDEX_op_ld32u_i64, { "r", "r" } },
1042 { INDEX_op_ld32s_i64, { "r", "r" } },
1043 { INDEX_op_ld_i64, { "r", "r" } },
1045 { INDEX_op_st8_i32, { "r", "r" } },
1046 { INDEX_op_st16_i32, { "r", "r" } },
1047 { INDEX_op_st_i32, { "r", "r" } },
1048 { INDEX_op_st8_i64, { "r", "r" } },
1049 { INDEX_op_st16_i64, { "r", "r" } },
1050 { INDEX_op_st32_i64, { "r", "r" } },
1051 { INDEX_op_st_i64, { "r", "r" } },
1053 { INDEX_op_add_i32, { "r", "r", "r" } },
1054 { INDEX_op_add_i64, { "r", "r", "r" } },
1055 { INDEX_op_sub_i32, { "r", "r", "r" } },
1056 { INDEX_op_sub_i64, { "r", "r", "r" } },
1057 { INDEX_op_mul_i32, { "r", "r", "r" } },
1058 { INDEX_op_mul_i64, { "r", "r", "r" } },
1059 { INDEX_op_and_i32, { "r", "r", "r" } },
1060 { INDEX_op_and_i64, { "r", "r", "r" } },
1061 { INDEX_op_or_i32, { "r", "r", "r" } },
1062 { INDEX_op_or_i64, { "r", "r", "r" } },
1063 { INDEX_op_xor_i32, { "r", "r", "r" } },
1064 { INDEX_op_xor_i64, { "r", "r", "r" } },
1066 { INDEX_op_shl_i32, { "r", "r", "ri" } },
1067 { INDEX_op_shr_i32, { "r", "r", "ri" } },
1068 { INDEX_op_sar_i32, { "r", "r", "ri" } },
1069 { INDEX_op_rotl_i32, { "r", "r", "ri" } },
1070 { INDEX_op_rotr_i32, { "r", "r", "ri" } },
1071 { INDEX_op_shl_i64, { "r", "r", "ri" } },
1072 { INDEX_op_shr_i64, { "r", "r", "ri" } },
1073 { INDEX_op_sar_i64, { "r", "r", "ri" } },
1074 { INDEX_op_rotl_i64, { "r", "r", "ri" } },
1075 { INDEX_op_rotr_i64, { "r", "r", "ri" } },
1077 { INDEX_op_brcond_i32, { "r", "r" } },
1078 { INDEX_op_setcond_i32, { "r", "r", "r" } },
1079 { INDEX_op_brcond_i64, { "r", "r" } },
1080 { INDEX_op_setcond_i64, { "r", "r", "r" } },
1082 { INDEX_op_qemu_ld8u, { "r", "l" } },
1083 { INDEX_op_qemu_ld8s, { "r", "l" } },
1084 { INDEX_op_qemu_ld16u, { "r", "l" } },
1085 { INDEX_op_qemu_ld16s, { "r", "l" } },
1086 { INDEX_op_qemu_ld32u, { "r", "l" } },
1087 { INDEX_op_qemu_ld32s, { "r", "l" } },
1089 { INDEX_op_qemu_ld32, { "r", "l" } },
1090 { INDEX_op_qemu_ld64, { "r", "l" } },
1092 { INDEX_op_qemu_st8, { "l", "l" } },
1093 { INDEX_op_qemu_st16, { "l", "l" } },
1094 { INDEX_op_qemu_st32, { "l", "l" } },
1095 { INDEX_op_qemu_st64, { "l", "l" } },
1096 { -1 },
1099 static void tcg_target_init(TCGContext *s)
1101 #if !defined(CONFIG_USER_ONLY)
1102 /* fail safe */
1103 if ((1ULL << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry)) {
1104 tcg_abort();
1106 #endif
1107 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff);
1108 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I64], 0, 0xffffffff);
1110 tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1111 (1 << TCG_REG_X0) | (1 << TCG_REG_X1) |
1112 (1 << TCG_REG_X2) | (1 << TCG_REG_X3) |
1113 (1 << TCG_REG_X4) | (1 << TCG_REG_X5) |
1114 (1 << TCG_REG_X6) | (1 << TCG_REG_X7) |
1115 (1 << TCG_REG_X8) | (1 << TCG_REG_X9) |
1116 (1 << TCG_REG_X10) | (1 << TCG_REG_X11) |
1117 (1 << TCG_REG_X12) | (1 << TCG_REG_X13) |
1118 (1 << TCG_REG_X14) | (1 << TCG_REG_X15) |
1119 (1 << TCG_REG_X16) | (1 << TCG_REG_X17) |
1120 (1 << TCG_REG_X18));
1122 tcg_regset_clear(s->reserved_regs);
1123 tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP);
1124 tcg_regset_set_reg(s->reserved_regs, TCG_REG_FP);
1125 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
1126 tcg_regset_set_reg(s->reserved_regs, TCG_REG_X18); /* platform register */
1128 tcg_add_target_add_op_defs(aarch64_op_defs);
1131 static inline void tcg_out_addi(TCGContext *s, int ext,
1132 TCGReg rd, TCGReg rn, unsigned int aimm)
1134 /* add immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */
1135 /* using ADD 0x11000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
1136 unsigned int base = ext ? 0x91000000 : 0x11000000;
1137 assert(aimm <= 0xfff);
1138 tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd);
1141 static inline void tcg_out_subi(TCGContext *s, int ext,
1142 TCGReg rd, TCGReg rn, unsigned int aimm)
1144 /* sub immediate aimm unsigned 12bit value (we use LSL 0 - no shift) */
1145 /* using SUB 0x51000000 | (ext) | (aimm << 10) | (rn << 5) | rd */
1146 unsigned int base = ext ? 0xd1000000 : 0x51000000;
1147 assert(aimm <= 0xfff);
1148 tcg_out32(s, base | (aimm << 10) | (rn << 5) | rd);
1151 static void tcg_target_qemu_prologue(TCGContext *s)
1153 /* NB: frame sizes are in 16 byte stack units! */
1154 int frame_size_callee_saved, frame_size_tcg_locals;
1155 TCGReg r;
1157 /* save pairs (FP, LR) and (X19, X20) .. (X27, X28) */
1158 frame_size_callee_saved = (1) + (TCG_REG_X28 - TCG_REG_X19) / 2 + 1;
1160 /* frame size requirement for TCG local variables */
1161 frame_size_tcg_locals = TCG_STATIC_CALL_ARGS_SIZE
1162 + CPU_TEMP_BUF_NLONGS * sizeof(long)
1163 + (TCG_TARGET_STACK_ALIGN - 1);
1164 frame_size_tcg_locals &= ~(TCG_TARGET_STACK_ALIGN - 1);
1165 frame_size_tcg_locals /= TCG_TARGET_STACK_ALIGN;
1167 /* push (FP, LR) and update sp */
1168 tcg_out_push_pair(s, TCG_REG_SP,
1169 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1171 /* FP -> callee_saved */
1172 tcg_out_movr_sp(s, 1, TCG_REG_FP, TCG_REG_SP);
1174 /* store callee-preserved regs x19..x28 using FP -> callee_saved */
1175 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1176 int idx = (r - TCG_REG_X19) / 2 + 1;
1177 tcg_out_store_pair(s, TCG_REG_FP, r, r + 1, idx);
1180 /* make stack space for TCG locals */
1181 tcg_out_subi(s, 1, TCG_REG_SP, TCG_REG_SP,
1182 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1183 /* inform TCG about how to find TCG locals with register, offset, size */
1184 tcg_set_frame(s, TCG_REG_SP, TCG_STATIC_CALL_ARGS_SIZE,
1185 CPU_TEMP_BUF_NLONGS * sizeof(long));
1187 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
1188 tcg_out_gotor(s, tcg_target_call_iarg_regs[1]);
1190 tb_ret_addr = s->code_ptr;
1192 /* remove TCG locals stack space */
1193 tcg_out_addi(s, 1, TCG_REG_SP, TCG_REG_SP,
1194 frame_size_tcg_locals * TCG_TARGET_STACK_ALIGN);
1196 /* restore registers x19..x28.
1197 FP must be preserved, so it still points to callee_saved area */
1198 for (r = TCG_REG_X19; r <= TCG_REG_X27; r += 2) {
1199 int idx = (r - TCG_REG_X19) / 2 + 1;
1200 tcg_out_load_pair(s, TCG_REG_FP, r, r + 1, idx);
1203 /* pop (FP, LR), restore SP to previous frame, return */
1204 tcg_out_pop_pair(s, TCG_REG_SP,
1205 TCG_REG_FP, TCG_REG_LR, frame_size_callee_saved);
1206 tcg_out_ret(s);