]> git.proxmox.com Git - mirror_qemu.git/blame - tcg/arm/tcg-target.inc.c
tcg: Remove tcg_regset_set32
[mirror_qemu.git] / tcg / arm / tcg-target.inc.c
CommitLineData
811d4cf4
AZ
1/*
2 * Tiny Code Generator for QEMU
3 *
4 * Copyright (c) 2008 Andrzej Zaborowski
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
d4a9eb1f 24
41d9ea80 25#include "elf.h"
880ad962 26#include "tcg-pool.inc.c"
9ecefc84 27
40b2ccb1 28int arm_arch = __ARM_ARCH;
ac34fb5c 29
72e1ccfc
RH
30#ifndef use_idiv_instructions
31bool use_idiv_instructions;
32#endif
72e1ccfc 33
1a8e80d7
RH
34/* ??? Ought to think about changing CONFIG_SOFTMMU to always defined. */
35#ifdef CONFIG_SOFTMMU
36# define USING_SOFTMMU 1
37#else
38# define USING_SOFTMMU 0
39#endif
40
8d8fdbae 41#ifdef CONFIG_DEBUG_TCG
d4a9eb1f 42static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
811d4cf4
AZ
43 "%r0",
44 "%r1",
45 "%r2",
46 "%r3",
47 "%r4",
48 "%r5",
49 "%r6",
50 "%r7",
51 "%r8",
52 "%r9",
53 "%r10",
54 "%r11",
55 "%r12",
56 "%r13",
57 "%r14",
e4a7d5e8 58 "%pc",
811d4cf4 59};
d4a9eb1f 60#endif
811d4cf4 61
d4a9eb1f 62static const int tcg_target_reg_alloc_order[] = {
811d4cf4
AZ
63 TCG_REG_R4,
64 TCG_REG_R5,
65 TCG_REG_R6,
66 TCG_REG_R7,
67 TCG_REG_R8,
68 TCG_REG_R9,
69 TCG_REG_R10,
70 TCG_REG_R11,
811d4cf4 71 TCG_REG_R13,
914ccf51
AJ
72 TCG_REG_R0,
73 TCG_REG_R1,
74 TCG_REG_R2,
75 TCG_REG_R3,
76 TCG_REG_R12,
811d4cf4
AZ
77 TCG_REG_R14,
78};
79
d4a9eb1f 80static const int tcg_target_call_iarg_regs[4] = {
811d4cf4
AZ
81 TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3
82};
d4a9eb1f 83static const int tcg_target_call_oarg_regs[2] = {
811d4cf4
AZ
84 TCG_REG_R0, TCG_REG_R1
85};
86
13dd6fb9 87#define TCG_REG_TMP TCG_REG_R12
4346457a 88
15070616
RH
89enum arm_cond_code_e {
90 COND_EQ = 0x0,
91 COND_NE = 0x1,
92 COND_CS = 0x2, /* Unsigned greater or equal */
93 COND_CC = 0x3, /* Unsigned less than */
94 COND_MI = 0x4, /* Negative */
95 COND_PL = 0x5, /* Zero or greater */
96 COND_VS = 0x6, /* Overflow */
97 COND_VC = 0x7, /* No overflow */
98 COND_HI = 0x8, /* Unsigned greater than */
99 COND_LS = 0x9, /* Unsigned less or equal */
100 COND_GE = 0xa,
101 COND_LT = 0xb,
102 COND_GT = 0xc,
103 COND_LE = 0xd,
104 COND_AL = 0xe,
105};
106
107#define TO_CPSR (1 << 20)
108
109#define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00)
110#define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20)
111#define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40)
112#define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60)
113#define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10)
114#define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30)
115#define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50)
116#define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70)
117
118typedef enum {
119 ARITH_AND = 0x0 << 21,
120 ARITH_EOR = 0x1 << 21,
121 ARITH_SUB = 0x2 << 21,
122 ARITH_RSB = 0x3 << 21,
123 ARITH_ADD = 0x4 << 21,
124 ARITH_ADC = 0x5 << 21,
125 ARITH_SBC = 0x6 << 21,
126 ARITH_RSC = 0x7 << 21,
127 ARITH_TST = 0x8 << 21 | TO_CPSR,
128 ARITH_CMP = 0xa << 21 | TO_CPSR,
129 ARITH_CMN = 0xb << 21 | TO_CPSR,
130 ARITH_ORR = 0xc << 21,
131 ARITH_MOV = 0xd << 21,
132 ARITH_BIC = 0xe << 21,
133 ARITH_MVN = 0xf << 21,
134
135 INSN_CLZ = 0x016f0f10,
136 INSN_RBIT = 0x06ff0f30,
137
138 INSN_LDR_IMM = 0x04100000,
139 INSN_LDR_REG = 0x06100000,
140 INSN_STR_IMM = 0x04000000,
141 INSN_STR_REG = 0x06000000,
142
143 INSN_LDRH_IMM = 0x005000b0,
144 INSN_LDRH_REG = 0x001000b0,
145 INSN_LDRSH_IMM = 0x005000f0,
146 INSN_LDRSH_REG = 0x001000f0,
147 INSN_STRH_IMM = 0x004000b0,
148 INSN_STRH_REG = 0x000000b0,
149
150 INSN_LDRB_IMM = 0x04500000,
151 INSN_LDRB_REG = 0x06500000,
152 INSN_LDRSB_IMM = 0x005000d0,
153 INSN_LDRSB_REG = 0x001000d0,
154 INSN_STRB_IMM = 0x04400000,
155 INSN_STRB_REG = 0x06400000,
156
157 INSN_LDRD_IMM = 0x004000d0,
158 INSN_LDRD_REG = 0x000000d0,
159 INSN_STRD_IMM = 0x004000f0,
160 INSN_STRD_REG = 0x000000f0,
161
162 INSN_DMB_ISH = 0x5bf07ff5,
163 INSN_DMB_MCR = 0xba0f07ee,
2a8ab93c
RH
164
165 /* Architected nop introduced in v6k. */
166 /* ??? This is an MSR (imm) 0,0,0 insn. Anyone know if this
167 also Just So Happened to do nothing on pre-v6k so that we
168 don't need to conditionalize it? */
169 INSN_NOP_v6k = 0xe320f000,
170 /* Otherwise the assembler uses mov r0,r0 */
171 INSN_NOP_v4 = (COND_AL << 28) | ARITH_MOV,
15070616
RH
172} ARMInsn;
173
2a8ab93c
RH
174#define INSN_NOP (use_armv7_instructions ? INSN_NOP_v6k : INSN_NOP_v4)
175
15070616
RH
176static const uint8_t tcg_cond_to_arm_cond[] = {
177 [TCG_COND_EQ] = COND_EQ,
178 [TCG_COND_NE] = COND_NE,
179 [TCG_COND_LT] = COND_LT,
180 [TCG_COND_GE] = COND_GE,
181 [TCG_COND_LE] = COND_LE,
182 [TCG_COND_GT] = COND_GT,
183 /* unsigned */
184 [TCG_COND_LTU] = COND_CC,
185 [TCG_COND_GEU] = COND_CS,
186 [TCG_COND_LEU] = COND_LS,
187 [TCG_COND_GTU] = COND_HI,
188};
189
267c9319 190static inline void reloc_pc24(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
c69806ab 191{
267c9319
RH
192 ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
193 *code_ptr = (*code_ptr & ~0xffffff) | (offset & 0xffffff);
c69806ab
AJ
194}
195
7d14e0e2
SF
196static inline void reloc_pc24_atomic(tcg_insn_unit *code_ptr, tcg_insn_unit *target)
197{
198 ptrdiff_t offset = (tcg_ptr_byte_diff(target, code_ptr) - 8) >> 2;
199 tcg_insn_unit insn = atomic_read(code_ptr);
200 tcg_debug_assert(offset == sextract32(offset, 0, 24));
201 atomic_set(code_ptr, deposit32(insn, 0, 24, offset));
202}
203
267c9319 204static void patch_reloc(tcg_insn_unit *code_ptr, int type,
2ba7fae2 205 intptr_t value, intptr_t addend)
811d4cf4 206{
eabb7b91 207 tcg_debug_assert(addend == 0);
880ad962
RH
208
209 if (type == R_ARM_PC24) {
210 reloc_pc24(code_ptr, (tcg_insn_unit *)value);
211 } else if (type == R_ARM_PC13) {
212 intptr_t diff = value - (uintptr_t)(code_ptr + 2);
213 tcg_insn_unit insn = *code_ptr;
214 bool u;
215
216 if (diff >= -0xfff && diff <= 0xfff) {
217 u = (diff >= 0);
218 if (!u) {
219 diff = -diff;
220 }
221 } else {
222 int rd = extract32(insn, 12, 4);
223 int rt = rd == TCG_REG_PC ? TCG_REG_TMP : rd;
224 assert(diff >= 0x1000 && diff < 0x100000);
225 /* add rt, pc, #high */
226 *code_ptr++ = ((insn & 0xf0000000) | (1 << 25) | ARITH_ADD
227 | (TCG_REG_PC << 16) | (rt << 12)
228 | (20 << 7) | (diff >> 12));
229 /* ldr rd, [rt, #low] */
230 insn = deposit32(insn, 12, 4, rt);
231 diff &= 0xfff;
232 u = 1;
233 }
234 insn = deposit32(insn, 23, 1, u);
235 insn = deposit32(insn, 0, 12, diff);
236 *code_ptr = insn;
237 } else {
238 g_assert_not_reached();
239 }
811d4cf4
AZ
240}
241
b6b24cb0
RH
242#define TCG_CT_CONST_ARM 0x100
243#define TCG_CT_CONST_INV 0x200
244#define TCG_CT_CONST_NEG 0x400
245#define TCG_CT_CONST_ZERO 0x800
19b62bf4 246
811d4cf4 247/* parse target specific constraints */
069ea736
RH
248static const char *target_parse_constraint(TCGArgConstraint *ct,
249 const char *ct_str, TCGType type)
811d4cf4 250{
069ea736 251 switch (*ct_str++) {
cb4e581f 252 case 'I':
19b62bf4
RH
253 ct->ct |= TCG_CT_CONST_ARM;
254 break;
255 case 'K':
256 ct->ct |= TCG_CT_CONST_INV;
257 break;
a9a86ae9
RH
258 case 'N': /* The gcc constraint letter is L, already used here. */
259 ct->ct |= TCG_CT_CONST_NEG;
260 break;
b6b24cb0
RH
261 case 'Z':
262 ct->ct |= TCG_CT_CONST_ZERO;
263 break;
cb4e581f 264
811d4cf4 265 case 'r':
811d4cf4 266 ct->ct |= TCG_CT_REG;
f46934df 267 ct->u.regs = 0xffff;
811d4cf4
AZ
268 break;
269
67dcab73
AJ
270 /* qemu_ld address */
271 case 'l':
811d4cf4 272 ct->ct |= TCG_CT_REG;
f46934df 273 ct->u.regs = 0xffff;
67dcab73 274#ifdef CONFIG_SOFTMMU
d9f4dde4 275 /* r0-r2,lr will be overwritten when reading the tlb entry,
67dcab73 276 so don't use these. */
811d4cf4
AZ
277 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
278 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
9716ef3b 279 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
d9f4dde4 280 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R14);
67dcab73 281#endif
d0660ed4
AZ
282 break;
283
a485cff0 284 /* qemu_st address & data */
67dcab73 285 case 's':
811d4cf4 286 ct->ct |= TCG_CT_REG;
f46934df 287 ct->u.regs = 0xffff;
702b33b1
RH
288 /* r0-r2 will be overwritten when reading the tlb entry (softmmu only)
289 and r0-r1 doing the byte swapping, so don't use these. */
811d4cf4 290 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
811d4cf4 291 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
702b33b1
RH
292#if defined(CONFIG_SOFTMMU)
293 /* Avoid clashes with registers being used for helper args */
67dcab73 294 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
89c33337 295#if TARGET_LONG_BITS == 64
9716ef3b
PM
296 /* Avoid clashes with registers being used for helper args */
297 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
298#endif
d9f4dde4 299 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R14);
811d4cf4 300#endif
67dcab73 301 break;
811d4cf4 302
811d4cf4 303 default:
069ea736 304 return NULL;
811d4cf4 305 }
069ea736 306 return ct_str;
811d4cf4
AZ
307}
308
94953e6d
LD
309static inline uint32_t rotl(uint32_t val, int n)
310{
311 return (val << n) | (val >> (32 - n));
312}
313
314/* ARM immediates for ALU instructions are made of an unsigned 8-bit
315 right-rotated by an even amount between 0 and 30. */
316static inline int encode_imm(uint32_t imm)
317{
4e6f6d4c
LD
318 int shift;
319
94953e6d
LD
320 /* simple case, only lower bits */
321 if ((imm & ~0xff) == 0)
322 return 0;
323 /* then try a simple even shift */
324 shift = ctz32(imm) & ~1;
325 if (((imm >> shift) & ~0xff) == 0)
326 return 32 - shift;
327 /* now try harder with rotations */
328 if ((rotl(imm, 2) & ~0xff) == 0)
329 return 2;
330 if ((rotl(imm, 4) & ~0xff) == 0)
331 return 4;
332 if ((rotl(imm, 6) & ~0xff) == 0)
333 return 6;
334 /* imm can't be encoded */
335 return -1;
336}
cb4e581f
LD
337
338static inline int check_fit_imm(uint32_t imm)
339{
94953e6d 340 return encode_imm(imm) >= 0;
cb4e581f
LD
341}
342
811d4cf4
AZ
343/* Test if a constant matches the constraint.
344 * TODO: define constraints for:
345 *
346 * ldr/str offset: between -0xfff and 0xfff
347 * ldrh/strh offset: between -0xff and 0xff
348 * mov operand2: values represented with x << (2 * y), x < 0x100
349 * add, sub, eor...: ditto
350 */
f6c6afc1 351static inline int tcg_target_const_match(tcg_target_long val, TCGType type,
19b62bf4 352 const TCGArgConstraint *arg_ct)
811d4cf4
AZ
353{
354 int ct;
355 ct = arg_ct->ct;
19b62bf4 356 if (ct & TCG_CT_CONST) {
811d4cf4 357 return 1;
19b62bf4 358 } else if ((ct & TCG_CT_CONST_ARM) && check_fit_imm(val)) {
cb4e581f 359 return 1;
19b62bf4
RH
360 } else if ((ct & TCG_CT_CONST_INV) && check_fit_imm(~val)) {
361 return 1;
a9a86ae9
RH
362 } else if ((ct & TCG_CT_CONST_NEG) && check_fit_imm(-val)) {
363 return 1;
b6b24cb0
RH
364 } else if ((ct & TCG_CT_CONST_ZERO) && val == 0) {
365 return 1;
19b62bf4 366 } else {
811d4cf4 367 return 0;
19b62bf4 368 }
811d4cf4
AZ
369}
370
15070616
RH
371static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
372{
373 tcg_out32(s, (cond << 28) | 0x0a000000 |
374 (((offset - 8) >> 2) & 0x00ffffff));
375}
2df3f1ee 376
15070616
RH
377static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
378{
379 /* We pay attention here to not modify the branch target by masking
380 the corresponding bytes. This ensure that caches and memory are
381 kept coherent during retranslation. */
382 tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0a));
383}
9feac1d7 384
15070616
RH
385static inline void tcg_out_bl_noaddr(TCGContext *s, int cond)
386{
387 /* We pay attention here to not modify the branch target by masking
388 the corresponding bytes. This ensure that caches and memory are
389 kept coherent during retranslation. */
390 tcg_out32(s, deposit32(*s->code_ptr, 24, 8, (cond << 4) | 0x0b));
391}
cc0fec8a 392
15070616
RH
393static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset)
394{
395 tcg_out32(s, (cond << 28) | 0x0b000000 |
396 (((offset - 8) >> 2) & 0x00ffffff));
397}
9feac1d7 398
15070616
RH
399static inline void tcg_out_blx(TCGContext *s, int cond, int rn)
400{
401 tcg_out32(s, (cond << 28) | 0x012fff30 | rn);
402}
9feac1d7 403
15070616
RH
404static inline void tcg_out_blx_imm(TCGContext *s, int32_t offset)
405{
406 tcg_out32(s, 0xfa000000 | ((offset & 2) << 23) |
407 (((offset - 8) >> 2) & 0x00ffffff));
408}
702b33b1 409
15070616
RH
410static inline void tcg_out_dat_reg(TCGContext *s,
411 int cond, int opc, int rd, int rn, int rm, int shift)
412{
413 tcg_out32(s, (cond << 28) | (0 << 25) | opc |
414 (rn << 16) | (rd << 12) | shift | rm);
415}
40f191ab 416
15070616
RH
417static inline void tcg_out_nop(TCGContext *s)
418{
2a8ab93c 419 tcg_out32(s, INSN_NOP);
15070616 420}
40f191ab 421
15070616
RH
422static inline void tcg_out_mov_reg(TCGContext *s, int cond, int rd, int rm)
423{
424 /* Simple reg-reg move, optimising out the 'do nothing' case */
425 if (rd != rm) {
426 tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, rm, SHIFT_IMM_LSL(0));
427 }
428}
811d4cf4 429
15070616
RH
430static inline void tcg_out_bx(TCGContext *s, int cond, TCGReg rn)
431{
432 /* Unless the C portion of QEMU is compiled as thumb, we don't
433 actually need true BX semantics; merely a branch to an address
434 held in a register. */
435 if (use_armv5t_instructions) {
436 tcg_out32(s, (cond << 28) | 0x012fff10 | rn);
437 } else {
438 tcg_out_mov_reg(s, cond, TCG_REG_PC, rn);
439 }
440}
811d4cf4 441
15070616
RH
442static inline void tcg_out_dat_imm(TCGContext *s,
443 int cond, int opc, int rd, int rn, int im)
444{
445 tcg_out32(s, (cond << 28) | (1 << 25) | opc |
446 (rn << 16) | (rd << 12) | im);
447}
811d4cf4 448
15070616
RH
449/* Note that this routine is used for both LDR and LDRH formats, so we do
450 not wish to include an immediate shift at this point. */
451static void tcg_out_memop_r(TCGContext *s, int cond, ARMInsn opc, TCGReg rt,
452 TCGReg rn, TCGReg rm, bool u, bool p, bool w)
453{
454 tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24)
455 | (w << 21) | (rn << 16) | (rt << 12) | rm);
456}
457
458static void tcg_out_memop_8(TCGContext *s, int cond, ARMInsn opc, TCGReg rt,
459 TCGReg rn, int imm8, bool p, bool w)
460{
461 bool u = 1;
462 if (imm8 < 0) {
463 imm8 = -imm8;
464 u = 0;
465 }
466 tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24) | (w << 21) |
467 (rn << 16) | (rt << 12) | ((imm8 & 0xf0) << 4) | (imm8 & 0xf));
468}
469
470static void tcg_out_memop_12(TCGContext *s, int cond, ARMInsn opc, TCGReg rt,
471 TCGReg rn, int imm12, bool p, bool w)
472{
473 bool u = 1;
474 if (imm12 < 0) {
475 imm12 = -imm12;
476 u = 0;
477 }
478 tcg_out32(s, (cond << 28) | opc | (u << 23) | (p << 24) | (w << 21) |
479 (rn << 16) | (rt << 12) | imm12);
480}
481
482static inline void tcg_out_ld32_12(TCGContext *s, int cond, TCGReg rt,
483 TCGReg rn, int imm12)
484{
485 tcg_out_memop_12(s, cond, INSN_LDR_IMM, rt, rn, imm12, 1, 0);
486}
487
488static inline void tcg_out_st32_12(TCGContext *s, int cond, TCGReg rt,
489 TCGReg rn, int imm12)
490{
491 tcg_out_memop_12(s, cond, INSN_STR_IMM, rt, rn, imm12, 1, 0);
492}
493
494static inline void tcg_out_ld32_r(TCGContext *s, int cond, TCGReg rt,
495 TCGReg rn, TCGReg rm)
496{
497 tcg_out_memop_r(s, cond, INSN_LDR_REG, rt, rn, rm, 1, 1, 0);
498}
499
500static inline void tcg_out_st32_r(TCGContext *s, int cond, TCGReg rt,
501 TCGReg rn, TCGReg rm)
502{
503 tcg_out_memop_r(s, cond, INSN_STR_REG, rt, rn, rm, 1, 1, 0);
504}
505
506static inline void tcg_out_ldrd_8(TCGContext *s, int cond, TCGReg rt,
507 TCGReg rn, int imm8)
508{
509 tcg_out_memop_8(s, cond, INSN_LDRD_IMM, rt, rn, imm8, 1, 0);
510}
511
512static inline void tcg_out_ldrd_r(TCGContext *s, int cond, TCGReg rt,
513 TCGReg rn, TCGReg rm)
514{
515 tcg_out_memop_r(s, cond, INSN_LDRD_REG, rt, rn, rm, 1, 1, 0);
516}
517
518static inline void tcg_out_strd_8(TCGContext *s, int cond, TCGReg rt,
519 TCGReg rn, int imm8)
520{
521 tcg_out_memop_8(s, cond, INSN_STRD_IMM, rt, rn, imm8, 1, 0);
522}
523
524static inline void tcg_out_strd_r(TCGContext *s, int cond, TCGReg rt,
525 TCGReg rn, TCGReg rm)
526{
527 tcg_out_memop_r(s, cond, INSN_STRD_REG, rt, rn, rm, 1, 1, 0);
528}
529
530/* Register pre-increment with base writeback. */
531static inline void tcg_out_ld32_rwb(TCGContext *s, int cond, TCGReg rt,
532 TCGReg rn, TCGReg rm)
533{
534 tcg_out_memop_r(s, cond, INSN_LDR_REG, rt, rn, rm, 1, 1, 1);
535}
536
537static inline void tcg_out_st32_rwb(TCGContext *s, int cond, TCGReg rt,
538 TCGReg rn, TCGReg rm)
539{
540 tcg_out_memop_r(s, cond, INSN_STR_REG, rt, rn, rm, 1, 1, 1);
541}
542
543static inline void tcg_out_ld16u_8(TCGContext *s, int cond, TCGReg rt,
544 TCGReg rn, int imm8)
545{
546 tcg_out_memop_8(s, cond, INSN_LDRH_IMM, rt, rn, imm8, 1, 0);
547}
811d4cf4 548
15070616
RH
549static inline void tcg_out_st16_8(TCGContext *s, int cond, TCGReg rt,
550 TCGReg rn, int imm8)
811d4cf4 551{
15070616 552 tcg_out_memop_8(s, cond, INSN_STRH_IMM, rt, rn, imm8, 1, 0);
811d4cf4
AZ
553}
554
15070616
RH
555static inline void tcg_out_ld16u_r(TCGContext *s, int cond, TCGReg rt,
556 TCGReg rn, TCGReg rm)
e936243a 557{
15070616 558 tcg_out_memop_r(s, cond, INSN_LDRH_REG, rt, rn, rm, 1, 1, 0);
d9f4dde4
RH
559}
560
15070616
RH
561static inline void tcg_out_st16_r(TCGContext *s, int cond, TCGReg rt,
562 TCGReg rn, TCGReg rm)
d9f4dde4 563{
15070616 564 tcg_out_memop_r(s, cond, INSN_STRH_REG, rt, rn, rm, 1, 1, 0);
e936243a
AZ
565}
566
15070616
RH
567static inline void tcg_out_ld16s_8(TCGContext *s, int cond, TCGReg rt,
568 TCGReg rn, int imm8)
811d4cf4 569{
15070616 570 tcg_out_memop_8(s, cond, INSN_LDRSH_IMM, rt, rn, imm8, 1, 0);
811d4cf4
AZ
571}
572
15070616
RH
573static inline void tcg_out_ld16s_r(TCGContext *s, int cond, TCGReg rt,
574 TCGReg rn, TCGReg rm)
23401b58 575{
15070616 576 tcg_out_memop_r(s, cond, INSN_LDRSH_REG, rt, rn, rm, 1, 1, 0);
23401b58
AJ
577}
578
15070616
RH
579static inline void tcg_out_ld8_12(TCGContext *s, int cond, TCGReg rt,
580 TCGReg rn, int imm12)
24e838b7 581{
15070616 582 tcg_out_memop_12(s, cond, INSN_LDRB_IMM, rt, rn, imm12, 1, 0);
24e838b7
PM
583}
584
15070616
RH
585static inline void tcg_out_st8_12(TCGContext *s, int cond, TCGReg rt,
586 TCGReg rn, int imm12)
811d4cf4 587{
15070616 588 tcg_out_memop_12(s, cond, INSN_STRB_IMM, rt, rn, imm12, 1, 0);
811d4cf4
AZ
589}
590
15070616
RH
591static inline void tcg_out_ld8_r(TCGContext *s, int cond, TCGReg rt,
592 TCGReg rn, TCGReg rm)
df5e0ef7 593{
15070616 594 tcg_out_memop_r(s, cond, INSN_LDRB_REG, rt, rn, rm, 1, 1, 0);
df5e0ef7
RH
595}
596
15070616
RH
597static inline void tcg_out_st8_r(TCGContext *s, int cond, TCGReg rt,
598 TCGReg rn, TCGReg rm)
9716ef3b 599{
15070616 600 tcg_out_memop_r(s, cond, INSN_STRB_REG, rt, rn, rm, 1, 1, 0);
9716ef3b
PM
601}
602
15070616
RH
603static inline void tcg_out_ld8s_8(TCGContext *s, int cond, TCGReg rt,
604 TCGReg rn, int imm8)
702a9474 605{
15070616 606 tcg_out_memop_8(s, cond, INSN_LDRSB_IMM, rt, rn, imm8, 1, 0);
702a9474
RH
607}
608
15070616
RH
609static inline void tcg_out_ld8s_r(TCGContext *s, int cond, TCGReg rt,
610 TCGReg rn, TCGReg rm)
811d4cf4 611{
15070616 612 tcg_out_memop_r(s, cond, INSN_LDRSB_REG, rt, rn, rm, 1, 1, 0);
811d4cf4
AZ
613}
614
880ad962
RH
615static void tcg_out_movi_pool(TCGContext *s, int cond, int rd, uint32_t arg)
616{
617 /* The 12-bit range on the ldr insn is sometimes a bit too small.
618 In order to get around that we require two insns, one of which
619 will usually be a nop, but may be replaced in patch_reloc. */
620 new_pool_label(s, arg, R_ARM_PC13, s->code_ptr, 0);
621 tcg_out_ld32_12(s, cond, rd, TCG_REG_PC, 0);
622 tcg_out_nop(s);
623}
624
e86e0f28 625static void tcg_out_movi32(TCGContext *s, int cond, int rd, uint32_t arg)
811d4cf4 626{
880ad962
RH
627 int rot, diff, opc, sh1, sh2;
628 uint32_t tt0, tt1, tt2;
9c39b94f
RH
629
630 /* Check a single MOV/MVN before anything else. */
631 rot = encode_imm(arg);
632 if (rot >= 0) {
633 tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0,
634 rotl(arg, rot) | (rot << 7));
635 return;
636 }
637 rot = encode_imm(~arg);
638 if (rot >= 0) {
639 tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0,
640 rotl(~arg, rot) | (rot << 7));
641 return;
642 }
643
644 /* Check for a pc-relative address. This will usually be the TB,
645 or within the TB, which is immediately before the code block. */
646 diff = arg - ((intptr_t)s->code_ptr + 8);
647 if (diff >= 0) {
648 rot = encode_imm(diff);
e86e0f28 649 if (rot >= 0) {
9c39b94f
RH
650 tcg_out_dat_imm(s, cond, ARITH_ADD, rd, TCG_REG_PC,
651 rotl(diff, rot) | (rot << 7));
e86e0f28
RH
652 return;
653 }
9c39b94f
RH
654 } else {
655 rot = encode_imm(-diff);
e86e0f28 656 if (rot >= 0) {
9c39b94f
RH
657 tcg_out_dat_imm(s, cond, ARITH_SUB, rd, TCG_REG_PC,
658 rotl(-diff, rot) | (rot << 7));
e86e0f28
RH
659 return;
660 }
661 }
662
663 /* Use movw + movt. */
664 if (use_armv7_instructions) {
ac34fb5c
AJ
665 /* movw */
666 tcg_out32(s, (cond << 28) | 0x03000000 | (rd << 12)
667 | ((arg << 4) & 0x000f0000) | (arg & 0xfff));
0f11f25a 668 if (arg & 0xffff0000) {
ac34fb5c
AJ
669 /* movt */
670 tcg_out32(s, (cond << 28) | 0x03400000 | (rd << 12)
671 | ((arg >> 12) & 0x000f0000) | ((arg >> 16) & 0xfff));
ac34fb5c 672 }
e86e0f28
RH
673 return;
674 }
0f11f25a 675
880ad962
RH
676 /* Look for sequences of two insns. If we have lots of 1's, we can
677 shorten the sequence by beginning with mvn and then clearing
678 higher bits with eor. */
679 tt0 = arg;
e86e0f28 680 opc = ARITH_MOV;
880ad962
RH
681 if (ctpop32(arg) > 16) {
682 tt0 = ~arg;
683 opc = ARITH_MVN;
684 }
685 sh1 = ctz32(tt0) & ~1;
686 tt1 = tt0 & ~(0xff << sh1);
687 sh2 = ctz32(tt1) & ~1;
688 tt2 = tt1 & ~(0xff << sh2);
689 if (tt2 == 0) {
690 rot = ((32 - sh1) << 7) & 0xf00;
691 tcg_out_dat_imm(s, cond, opc, rd, 0, ((tt0 >> sh1) & 0xff) | rot);
692 rot = ((32 - sh2) << 7) & 0xf00;
693 tcg_out_dat_imm(s, cond, ARITH_EOR, rd, rd,
694 ((tt0 >> sh2) & 0xff) | rot);
695 return;
0f11f25a 696 }
e86e0f28 697
880ad962
RH
698 /* Otherwise, drop it into the constant pool. */
699 tcg_out_movi_pool(s, cond, rd, arg);
811d4cf4
AZ
700}
701
7fc645bf
PM
702static inline void tcg_out_dat_rI(TCGContext *s, int cond, int opc, TCGArg dst,
703 TCGArg lhs, TCGArg rhs, int rhs_is_const)
704{
705 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
706 * rhs must satisfy the "rI" constraint.
707 */
708 if (rhs_is_const) {
709 int rot = encode_imm(rhs);
eabb7b91 710 tcg_debug_assert(rot >= 0);
7fc645bf
PM
711 tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
712 } else {
713 tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
714 }
715}
716
19b62bf4
RH
717static void tcg_out_dat_rIK(TCGContext *s, int cond, int opc, int opinv,
718 TCGReg dst, TCGReg lhs, TCGArg rhs,
719 bool rhs_is_const)
720{
721 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
722 * rhs must satisfy the "rIK" constraint.
723 */
724 if (rhs_is_const) {
725 int rot = encode_imm(rhs);
726 if (rot < 0) {
727 rhs = ~rhs;
728 rot = encode_imm(rhs);
eabb7b91 729 tcg_debug_assert(rot >= 0);
19b62bf4
RH
730 opc = opinv;
731 }
732 tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
733 } else {
734 tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
735 }
736}
737
a9a86ae9
RH
738static void tcg_out_dat_rIN(TCGContext *s, int cond, int opc, int opneg,
739 TCGArg dst, TCGArg lhs, TCGArg rhs,
740 bool rhs_is_const)
741{
742 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
743 * rhs must satisfy the "rIN" constraint.
744 */
745 if (rhs_is_const) {
746 int rot = encode_imm(rhs);
747 if (rot < 0) {
748 rhs = -rhs;
749 rot = encode_imm(rhs);
eabb7b91 750 tcg_debug_assert(rot >= 0);
a9a86ae9
RH
751 opc = opneg;
752 }
753 tcg_out_dat_imm(s, cond, opc, dst, lhs, rotl(rhs, rot) | (rot << 7));
754 } else {
755 tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0));
756 }
757}
758
34358a12
RH
759static inline void tcg_out_mul32(TCGContext *s, int cond, TCGReg rd,
760 TCGReg rn, TCGReg rm)
811d4cf4 761{
34358a12
RH
762 /* if ArchVersion() < 6 && d == n then UNPREDICTABLE; */
763 if (!use_armv6_instructions && rd == rn) {
764 if (rd == rm) {
765 /* rd == rn == rm; copy an input to tmp first. */
766 tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
767 rm = rn = TCG_REG_TMP;
768 } else {
769 rn = rm;
770 rm = rd;
771 }
811d4cf4 772 }
34358a12
RH
773 /* mul */
774 tcg_out32(s, (cond << 28) | 0x90 | (rd << 16) | (rm << 8) | rn);
811d4cf4
AZ
775}
776
34358a12
RH
777static inline void tcg_out_umull32(TCGContext *s, int cond, TCGReg rd0,
778 TCGReg rd1, TCGReg rn, TCGReg rm)
811d4cf4 779{
34358a12
RH
780 /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
781 if (!use_armv6_instructions && (rd0 == rn || rd1 == rn)) {
782 if (rd0 == rm || rd1 == rm) {
783 tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
784 rn = TCG_REG_TMP;
785 } else {
786 TCGReg t = rn;
787 rn = rm;
788 rm = t;
789 }
811d4cf4 790 }
34358a12
RH
791 /* umull */
792 tcg_out32(s, (cond << 28) | 0x00800090 |
793 (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn);
811d4cf4
AZ
794}
795
34358a12
RH
796static inline void tcg_out_smull32(TCGContext *s, int cond, TCGReg rd0,
797 TCGReg rd1, TCGReg rn, TCGReg rm)
811d4cf4 798{
34358a12
RH
799 /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
800 if (!use_armv6_instructions && (rd0 == rn || rd1 == rn)) {
801 if (rd0 == rm || rd1 == rm) {
802 tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
803 rn = TCG_REG_TMP;
804 } else {
805 TCGReg t = rn;
806 rn = rm;
807 rm = t;
808 }
811d4cf4 809 }
34358a12
RH
810 /* smull */
811 tcg_out32(s, (cond << 28) | 0x00c00090 |
812 (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn);
811d4cf4
AZ
813}
814
0637c56c
RH
815static inline void tcg_out_sdiv(TCGContext *s, int cond, int rd, int rn, int rm)
816{
817 tcg_out32(s, 0x0710f010 | (cond << 28) | (rd << 16) | rn | (rm << 8));
818}
819
820static inline void tcg_out_udiv(TCGContext *s, int cond, int rd, int rn, int rm)
821{
822 tcg_out32(s, 0x0730f010 | (cond << 28) | (rd << 16) | rn | (rm << 8));
823}
824
9517094f
AJ
825static inline void tcg_out_ext8s(TCGContext *s, int cond,
826 int rd, int rn)
827{
828 if (use_armv6_instructions) {
829 /* sxtb */
830 tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | rn);
831 } else {
e23886a9 832 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f 833 rd, 0, rn, SHIFT_IMM_LSL(24));
e23886a9 834 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f
AJ
835 rd, 0, rd, SHIFT_IMM_ASR(24));
836 }
837}
838
e854b6d3
AJ
839static inline void tcg_out_ext8u(TCGContext *s, int cond,
840 int rd, int rn)
841{
842 tcg_out_dat_imm(s, cond, ARITH_AND, rd, rn, 0xff);
843}
844
9517094f
AJ
845static inline void tcg_out_ext16s(TCGContext *s, int cond,
846 int rd, int rn)
847{
848 if (use_armv6_instructions) {
849 /* sxth */
850 tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | rn);
851 } else {
e23886a9 852 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f 853 rd, 0, rn, SHIFT_IMM_LSL(16));
e23886a9 854 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f
AJ
855 rd, 0, rd, SHIFT_IMM_ASR(16));
856 }
857}
858
859static inline void tcg_out_ext16u(TCGContext *s, int cond,
860 int rd, int rn)
861{
862 if (use_armv6_instructions) {
863 /* uxth */
864 tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rn);
865 } else {
e23886a9 866 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f 867 rd, 0, rn, SHIFT_IMM_LSL(16));
e23886a9 868 tcg_out_dat_reg(s, cond, ARITH_MOV,
9517094f
AJ
869 rd, 0, rd, SHIFT_IMM_LSR(16));
870 }
871}
872
67dcab73
AJ
873static inline void tcg_out_bswap16s(TCGContext *s, int cond, int rd, int rn)
874{
875 if (use_armv6_instructions) {
876 /* revsh */
877 tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn);
878 } else {
879 tcg_out_dat_reg(s, cond, ARITH_MOV,
4346457a 880 TCG_REG_TMP, 0, rn, SHIFT_IMM_LSL(24));
67dcab73 881 tcg_out_dat_reg(s, cond, ARITH_MOV,
4346457a 882 TCG_REG_TMP, 0, TCG_REG_TMP, SHIFT_IMM_ASR(16));
67dcab73 883 tcg_out_dat_reg(s, cond, ARITH_ORR,
4346457a 884 rd, TCG_REG_TMP, rn, SHIFT_IMM_LSR(8));
67dcab73
AJ
885 }
886}
887
244b1e81
AJ
888static inline void tcg_out_bswap16(TCGContext *s, int cond, int rd, int rn)
889{
890 if (use_armv6_instructions) {
891 /* rev16 */
892 tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
893 } else {
894 tcg_out_dat_reg(s, cond, ARITH_MOV,
4346457a 895 TCG_REG_TMP, 0, rn, SHIFT_IMM_LSL(24));
244b1e81 896 tcg_out_dat_reg(s, cond, ARITH_MOV,
4346457a 897 TCG_REG_TMP, 0, TCG_REG_TMP, SHIFT_IMM_LSR(16));
244b1e81 898 tcg_out_dat_reg(s, cond, ARITH_ORR,
4346457a 899 rd, TCG_REG_TMP, rn, SHIFT_IMM_LSR(8));
244b1e81
AJ
900 }
901}
902
7aab08aa
AJ
903/* swap the two low bytes assuming that the two high input bytes and the
904 two high output bit can hold any value. */
905static inline void tcg_out_bswap16st(TCGContext *s, int cond, int rd, int rn)
906{
907 if (use_armv6_instructions) {
908 /* rev16 */
909 tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
910 } else {
911 tcg_out_dat_reg(s, cond, ARITH_MOV,
4346457a
RH
912 TCG_REG_TMP, 0, rn, SHIFT_IMM_LSR(8));
913 tcg_out_dat_imm(s, cond, ARITH_AND, TCG_REG_TMP, TCG_REG_TMP, 0xff);
7aab08aa 914 tcg_out_dat_reg(s, cond, ARITH_ORR,
4346457a 915 rd, TCG_REG_TMP, rn, SHIFT_IMM_LSL(8));
7aab08aa
AJ
916 }
917}
918
244b1e81
AJ
919static inline void tcg_out_bswap32(TCGContext *s, int cond, int rd, int rn)
920{
921 if (use_armv6_instructions) {
922 /* rev */
923 tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn);
924 } else {
925 tcg_out_dat_reg(s, cond, ARITH_EOR,
4346457a 926 TCG_REG_TMP, rn, rn, SHIFT_IMM_ROR(16));
244b1e81 927 tcg_out_dat_imm(s, cond, ARITH_BIC,
4346457a 928 TCG_REG_TMP, TCG_REG_TMP, 0xff | 0x800);
244b1e81
AJ
929 tcg_out_dat_reg(s, cond, ARITH_MOV,
930 rd, 0, rn, SHIFT_IMM_ROR(8));
931 tcg_out_dat_reg(s, cond, ARITH_EOR,
4346457a 932 rd, rd, TCG_REG_TMP, SHIFT_IMM_LSR(8));
244b1e81
AJ
933 }
934}
935
b6b24cb0
RH
936static inline void tcg_out_deposit(TCGContext *s, int cond, TCGReg rd,
937 TCGArg a1, int ofs, int len, bool const_a1)
938{
939 if (const_a1) {
940 /* bfi becomes bfc with rn == 15. */
941 a1 = 15;
942 }
943 /* bfi/bfc */
944 tcg_out32(s, 0x07c00010 | (cond << 28) | (rd << 12) | a1
945 | (ofs << 7) | ((ofs + len - 1) << 16));
946}
947
ec903af1
RH
948static inline void tcg_out_extract(TCGContext *s, int cond, TCGReg rd,
949 TCGArg a1, int ofs, int len)
950{
951 /* ubfx */
952 tcg_out32(s, 0x07e00050 | (cond << 28) | (rd << 12) | a1
953 | (ofs << 7) | ((len - 1) << 16));
954}
955
956static inline void tcg_out_sextract(TCGContext *s, int cond, TCGReg rd,
957 TCGArg a1, int ofs, int len)
958{
959 /* sbfx */
960 tcg_out32(s, 0x07a00050 | (cond << 28) | (rd << 12) | a1
961 | (ofs << 7) | ((len - 1) << 16));
962}
963
811d4cf4
AZ
964static inline void tcg_out_ld32u(TCGContext *s, int cond,
965 int rd, int rn, int32_t offset)
966{
967 if (offset > 0xfff || offset < -0xfff) {
4346457a
RH
968 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
969 tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
970 } else
971 tcg_out_ld32_12(s, cond, rd, rn, offset);
972}
973
974static inline void tcg_out_st32(TCGContext *s, int cond,
975 int rd, int rn, int32_t offset)
976{
977 if (offset > 0xfff || offset < -0xfff) {
4346457a
RH
978 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
979 tcg_out_st32_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
980 } else
981 tcg_out_st32_12(s, cond, rd, rn, offset);
982}
983
984static inline void tcg_out_ld16u(TCGContext *s, int cond,
985 int rd, int rn, int32_t offset)
986{
987 if (offset > 0xff || offset < -0xff) {
4346457a
RH
988 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
989 tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
990 } else
991 tcg_out_ld16u_8(s, cond, rd, rn, offset);
992}
993
994static inline void tcg_out_ld16s(TCGContext *s, int cond,
995 int rd, int rn, int32_t offset)
996{
997 if (offset > 0xff || offset < -0xff) {
4346457a
RH
998 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
999 tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
1000 } else
1001 tcg_out_ld16s_8(s, cond, rd, rn, offset);
1002}
1003
f694a27e 1004static inline void tcg_out_st16(TCGContext *s, int cond,
811d4cf4
AZ
1005 int rd, int rn, int32_t offset)
1006{
1007 if (offset > 0xff || offset < -0xff) {
4346457a
RH
1008 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
1009 tcg_out_st16_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4 1010 } else
f694a27e 1011 tcg_out_st16_8(s, cond, rd, rn, offset);
811d4cf4
AZ
1012}
1013
1014static inline void tcg_out_ld8u(TCGContext *s, int cond,
1015 int rd, int rn, int32_t offset)
1016{
1017 if (offset > 0xfff || offset < -0xfff) {
4346457a
RH
1018 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
1019 tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
1020 } else
1021 tcg_out_ld8_12(s, cond, rd, rn, offset);
1022}
1023
1024static inline void tcg_out_ld8s(TCGContext *s, int cond,
1025 int rd, int rn, int32_t offset)
1026{
1027 if (offset > 0xff || offset < -0xff) {
4346457a
RH
1028 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
1029 tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
1030 } else
1031 tcg_out_ld8s_8(s, cond, rd, rn, offset);
1032}
1033
f694a27e 1034static inline void tcg_out_st8(TCGContext *s, int cond,
811d4cf4
AZ
1035 int rd, int rn, int32_t offset)
1036{
1037 if (offset > 0xfff || offset < -0xfff) {
4346457a
RH
1038 tcg_out_movi32(s, cond, TCG_REG_TMP, offset);
1039 tcg_out_st8_r(s, cond, rd, rn, TCG_REG_TMP);
811d4cf4
AZ
1040 } else
1041 tcg_out_st8_12(s, cond, rd, rn, offset);
1042}
1043
d9f4dde4
RH
1044/* The _goto case is normally between TBs within the same code buffer, and
1045 * with the code buffer limited to 16MB we wouldn't need the long case.
1046 * But we also use it for the tail-call to the qemu_ld/st helpers, which does.
222f23f5 1047 */
702a9474 1048static void tcg_out_goto(TCGContext *s, int cond, tcg_insn_unit *addr)
811d4cf4 1049{
267c9319
RH
1050 intptr_t addri = (intptr_t)addr;
1051 ptrdiff_t disp = tcg_pcrel_diff(s, addr);
811d4cf4 1052
267c9319 1053 if ((addri & 1) == 0 && disp - 8 < 0x01fffffd && disp - 8 > -0x01fffffd) {
d9f4dde4
RH
1054 tcg_out_b(s, cond, disp);
1055 return;
24e838b7 1056 }
afe74dbd 1057 tcg_out_movi_pool(s, cond, TCG_REG_PC, addri);
811d4cf4
AZ
1058}
1059
222f23f5
DDAG
1060/* The call case is mostly used for helpers - so it's not unreasonable
1061 * for them to be beyond branch range */
267c9319 1062static void tcg_out_call(TCGContext *s, tcg_insn_unit *addr)
811d4cf4 1063{
267c9319
RH
1064 intptr_t addri = (intptr_t)addr;
1065 ptrdiff_t disp = tcg_pcrel_diff(s, addr);
811d4cf4 1066
267c9319
RH
1067 if (disp - 8 < 0x02000000 && disp - 8 >= -0x02000000) {
1068 if (addri & 1) {
24e838b7 1069 /* Use BLX if the target is in Thumb mode */
fb822738 1070 if (!use_armv5t_instructions) {
24e838b7
PM
1071 tcg_abort();
1072 }
267c9319 1073 tcg_out_blx_imm(s, disp);
24e838b7 1074 } else {
267c9319 1075 tcg_out_bl(s, COND_AL, disp);
24e838b7 1076 }
302fdde7 1077 } else if (use_armv7_instructions) {
267c9319 1078 tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
302fdde7 1079 tcg_out_blx(s, COND_AL, TCG_REG_TMP);
24e838b7 1080 } else {
afe74dbd 1081 /* ??? Know that movi_pool emits exactly 2 insns. */
222f23f5 1082 tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R14, TCG_REG_PC, 4);
afe74dbd 1083 tcg_out_movi_pool(s, COND_AL, TCG_REG_PC, addri);
811d4cf4 1084 }
811d4cf4
AZ
1085}
1086
bec16311 1087static inline void tcg_out_goto_label(TCGContext *s, int cond, TCGLabel *l)
811d4cf4 1088{
96fbd7de 1089 if (l->has_value) {
267c9319 1090 tcg_out_goto(s, cond, l->u.value_ptr);
811d4cf4 1091 } else {
bec16311 1092 tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, l, 0);
e936243a 1093 tcg_out_b_noaddr(s, cond);
811d4cf4
AZ
1094 }
1095}
1096
40f191ab
PK
1097static inline void tcg_out_mb(TCGContext *s, TCGArg a0)
1098{
1099 if (use_armv7_instructions) {
1100 tcg_out32(s, INSN_DMB_ISH);
1101 } else if (use_armv6_instructions) {
1102 tcg_out32(s, INSN_DMB_MCR);
1103 }
1104}
1105
811d4cf4 1106#ifdef CONFIG_SOFTMMU
659ef5cb
RH
1107#include "tcg-ldst.inc.c"
1108
d9f4dde4
RH
1109/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
1110 * int mmu_idx, uintptr_t ra)
1111 */
267c9319 1112static void * const qemu_ld_helpers[16] = {
0315c51e
RH
1113 [MO_UB] = helper_ret_ldub_mmu,
1114 [MO_SB] = helper_ret_ldsb_mmu,
1115
1116 [MO_LEUW] = helper_le_lduw_mmu,
1117 [MO_LEUL] = helper_le_ldul_mmu,
1118 [MO_LEQ] = helper_le_ldq_mmu,
1119 [MO_LESW] = helper_le_ldsw_mmu,
1120 [MO_LESL] = helper_le_ldul_mmu,
1121
1122 [MO_BEUW] = helper_be_lduw_mmu,
1123 [MO_BEUL] = helper_be_ldul_mmu,
1124 [MO_BEQ] = helper_be_ldq_mmu,
1125 [MO_BESW] = helper_be_ldsw_mmu,
1126 [MO_BESL] = helper_be_ldul_mmu,
e141ab52
BS
1127};
1128
d9f4dde4
RH
1129/* helper signature: helper_ret_st_mmu(CPUState *env, target_ulong addr,
1130 * uintxx_t val, int mmu_idx, uintptr_t ra)
1131 */
267c9319 1132static void * const qemu_st_helpers[16] = {
0315c51e
RH
1133 [MO_UB] = helper_ret_stb_mmu,
1134 [MO_LEUW] = helper_le_stw_mmu,
1135 [MO_LEUL] = helper_le_stl_mmu,
1136 [MO_LEQ] = helper_le_stq_mmu,
1137 [MO_BEUW] = helper_be_stw_mmu,
1138 [MO_BEUL] = helper_be_stl_mmu,
1139 [MO_BEQ] = helper_be_stq_mmu,
e141ab52 1140};
9716ef3b
PM
1141
1142/* Helper routines for marshalling helper function arguments into
1143 * the correct registers and stack.
1144 * argreg is where we want to put this argument, arg is the argument itself.
1145 * Return value is the updated argreg ready for the next call.
1146 * Note that argreg 0..3 is real registers, 4+ on stack.
9716ef3b
PM
1147 *
1148 * We provide routines for arguments which are: immediate, 32 bit
1149 * value in register, 16 and 8 bit values in register (which must be zero
1150 * extended before use) and 64 bit value in a lo:hi register pair.
1151 */
fc4d60ee
RH
1152#define DEFINE_TCG_OUT_ARG(NAME, ARGTYPE, MOV_ARG, EXT_ARG) \
1153static TCGReg NAME(TCGContext *s, TCGReg argreg, ARGTYPE arg) \
1154{ \
1155 if (argreg < 4) { \
1156 MOV_ARG(s, COND_AL, argreg, arg); \
1157 } else { \
1158 int ofs = (argreg - 4) * 4; \
1159 EXT_ARG; \
eabb7b91 1160 tcg_debug_assert(ofs + 4 <= TCG_STATIC_CALL_ARGS_SIZE); \
fc4d60ee
RH
1161 tcg_out_st32_12(s, COND_AL, arg, TCG_REG_CALL_STACK, ofs); \
1162 } \
1163 return argreg + 1; \
1164}
1165
1166DEFINE_TCG_OUT_ARG(tcg_out_arg_imm32, uint32_t, tcg_out_movi32,
4346457a 1167 (tcg_out_movi32(s, COND_AL, TCG_REG_TMP, arg), arg = TCG_REG_TMP))
fc4d60ee 1168DEFINE_TCG_OUT_ARG(tcg_out_arg_reg8, TCGReg, tcg_out_ext8u,
4346457a 1169 (tcg_out_ext8u(s, COND_AL, TCG_REG_TMP, arg), arg = TCG_REG_TMP))
fc4d60ee 1170DEFINE_TCG_OUT_ARG(tcg_out_arg_reg16, TCGReg, tcg_out_ext16u,
4346457a 1171 (tcg_out_ext16u(s, COND_AL, TCG_REG_TMP, arg), arg = TCG_REG_TMP))
fc4d60ee
RH
1172DEFINE_TCG_OUT_ARG(tcg_out_arg_reg32, TCGReg, tcg_out_mov_reg, )
1173
1174static TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,
1175 TCGReg arglo, TCGReg arghi)
9716ef3b
PM
1176{
1177 /* 64 bit arguments must go in even/odd register pairs
1178 * and in 8-aligned stack slots.
1179 */
1180 if (argreg & 1) {
1181 argreg++;
1182 }
e5e2e4a7
RH
1183 if (use_armv6_instructions && argreg >= 4
1184 && (arglo & 1) == 0 && arghi == arglo + 1) {
1185 tcg_out_strd_8(s, COND_AL, arglo,
1186 TCG_REG_CALL_STACK, (argreg - 4) * 4);
1187 return argreg + 2;
1188 } else {
1189 argreg = tcg_out_arg_reg32(s, argreg, arglo);
1190 argreg = tcg_out_arg_reg32(s, argreg, arghi);
1191 return argreg;
1192 }
9716ef3b 1193}
811d4cf4 1194
3979144c
PB
1195#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
1196
f2488736
RH
1197/* We're expecting to use an 8-bit immediate and to mask. */
1198QEMU_BUILD_BUG_ON(CPU_TLB_BITS > 8);
1199
1200/* We're expecting to use an 8-bit immediate add + 8-bit ldrd offset.
1201 Using the offset of the second entry in the last tlb table ensures
1202 that we can index all of the elements of the first entry. */
1203QEMU_BUILD_BUG_ON(offsetof(CPUArchState, tlb_table[NB_MMU_MODES - 1][1])
1204 > 0xffff);
1205
d3e440be
RH
1206/* Load and compare a TLB entry, leaving the flags set. Returns the register
1207 containing the addend of the tlb entry. Clobbers R0, R1, R2, TMP. */
811d4cf4 1208
d3e440be 1209static TCGReg tcg_out_tlb_read(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
85aa8081 1210 TCGMemOp opc, int mem_index, bool is_load)
cee87be8 1211{
702b33b1 1212 TCGReg base = TCG_AREG0;
d0ebde22
RH
1213 int cmp_off =
1214 (is_load
1215 ? offsetof(CPUArchState, tlb_table[mem_index][0].addr_read)
1216 : offsetof(CPUArchState, tlb_table[mem_index][0].addr_write));
1217 int add_off = offsetof(CPUArchState, tlb_table[mem_index][0].addend);
85aa8081
RH
1218 unsigned s_bits = opc & MO_SIZE;
1219 unsigned a_bits = get_alignment_bits(opc);
702b33b1 1220
647ab96a
RH
1221 /* V7 generates the following:
1222 * ubfx r0, addrlo, #TARGET_PAGE_BITS, #CPU_TLB_BITS
d0ebde22 1223 * add r2, env, #high
647ab96a
RH
1224 * add r2, r2, r0, lsl #CPU_TLB_ENTRY_BITS
1225 * ldr r0, [r2, #cmp]
1226 * ldr r2, [r2, #add]
1227 * movw tmp, #page_align_mask
1228 * bic tmp, addrlo, tmp
1229 * cmp r0, tmp
1230 *
1231 * Otherwise we generate:
1232 * shr tmp, addrlo, #TARGET_PAGE_BITS
1233 * add r2, env, #high
1234 * and r0, tmp, #(CPU_TLB_SIZE - 1)
1235 * add r2, r2, r0, lsl #CPU_TLB_ENTRY_BITS
1236 * ldr r0, [r2, #cmp]
1237 * ldr r2, [r2, #add]
a485cff0 1238 * tst addrlo, #s_mask
ee06e230 1239 * cmpeq r0, tmp, lsl #TARGET_PAGE_BITS
91a3c1b0 1240 */
647ab96a
RH
1241 if (use_armv7_instructions) {
1242 tcg_out_extract(s, COND_AL, TCG_REG_R0, addrlo,
1243 TARGET_PAGE_BITS, CPU_TLB_BITS);
1244 } else {
1245 tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP,
1246 0, addrlo, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
1247 }
702b33b1 1248
f2488736 1249 /* We checked that the offset is contained within 16 bits above. */
95ede84f
RH
1250 if (add_off > 0xfff
1251 || (use_armv6_instructions && TARGET_LONG_BITS == 64
1252 && cmp_off > 0xff)) {
702b33b1 1253 tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R2, base,
d0ebde22 1254 (24 << 7) | (cmp_off >> 8));
702b33b1 1255 base = TCG_REG_R2;
d0ebde22
RH
1256 add_off -= cmp_off & 0xff00;
1257 cmp_off &= 0xff;
702b33b1 1258 }
647ab96a
RH
1259 if (!use_armv7_instructions) {
1260 tcg_out_dat_imm(s, COND_AL, ARITH_AND,
1261 TCG_REG_R0, TCG_REG_TMP, CPU_TLB_SIZE - 1);
1262 }
702b33b1 1263 tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_R2, base,
c8d80cef 1264 TCG_REG_R0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
cee87be8 1265
702b33b1
RH
1266 /* Load the tlb comparator. Use ldrd if needed and available,
1267 but due to how the pointer needs setting up, ldm isn't useful.
1268 Base arm5 doesn't have ldrd, but armv5te does. */
1269 if (use_armv6_instructions && TARGET_LONG_BITS == 64) {
d0ebde22 1270 tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_REG_R2, cmp_off);
702b33b1 1271 } else {
d0ebde22 1272 tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, TCG_REG_R2, cmp_off);
702b33b1 1273 if (TARGET_LONG_BITS == 64) {
d0ebde22 1274 tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R2, cmp_off + 4);
702b33b1 1275 }
d17bd1d8 1276 }
cee87be8 1277
647ab96a
RH
1278 /* Load the tlb addend. */
1279 tcg_out_ld32_12(s, COND_AL, TCG_REG_R2, TCG_REG_R2, add_off);
1280
85aa8081
RH
1281 /* Check alignment. We don't support inline unaligned acceses,
1282 but we can easily support overalignment checks. */
1283 if (a_bits < s_bits) {
1284 a_bits = s_bits;
1285 }
cee87be8 1286
647ab96a
RH
1287 if (use_armv7_instructions) {
1288 tcg_target_ulong mask = ~(TARGET_PAGE_MASK | ((1 << a_bits) - 1));
1289 int rot = encode_imm(mask);
ee06e230 1290
647ab96a
RH
1291 if (rot >= 0) {
1292 tcg_out_dat_imm(s, COND_AL, ARITH_BIC, TCG_REG_TMP, addrlo,
1293 rotl(mask, rot) | (rot << 7));
1294 } else {
1295 tcg_out_movi32(s, COND_AL, TCG_REG_TMP, mask);
1296 tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP,
1297 addrlo, TCG_REG_TMP, 0);
1298 }
1299 tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R0, TCG_REG_TMP, 0);
1300 } else {
1301 if (a_bits) {
1302 tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo,
1303 (1 << a_bits) - 1);
1304 }
1305 tcg_out_dat_reg(s, (a_bits ? COND_EQ : COND_AL), ARITH_CMP,
1306 0, TCG_REG_R0, TCG_REG_TMP,
1307 SHIFT_IMM_LSL(TARGET_PAGE_BITS));
1308 }
702b33b1 1309
cee87be8 1310 if (TARGET_LONG_BITS == 64) {
647ab96a 1311 tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0, TCG_REG_R1, addrhi, 0);
cee87be8 1312 }
d0ebde22 1313
ee06e230 1314 return TCG_REG_R2;
cee87be8 1315}
df5e0ef7
RH
1316
1317/* Record the context of a call to the out of line helper code for the slow
1318 path for a load or store, so that we can later generate the correct
1319 helper code. */
3972ef6f 1320static void add_qemu_ldst_label(TCGContext *s, bool is_ld, TCGMemOpIdx oi,
a485cff0 1321 TCGReg datalo, TCGReg datahi, TCGReg addrlo,
3972ef6f
RH
1322 TCGReg addrhi, tcg_insn_unit *raddr,
1323 tcg_insn_unit *label_ptr)
df5e0ef7 1324{
9ecefc84 1325 TCGLabelQemuLdst *label = new_ldst_label(s);
df5e0ef7 1326
df5e0ef7 1327 label->is_ld = is_ld;
3972ef6f 1328 label->oi = oi;
a485cff0
RH
1329 label->datalo_reg = datalo;
1330 label->datahi_reg = datahi;
1331 label->addrlo_reg = addrlo;
1332 label->addrhi_reg = addrhi;
df5e0ef7
RH
1333 label->raddr = raddr;
1334 label->label_ptr[0] = label_ptr;
1335}
1336
1337static void tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
1338{
a485cff0 1339 TCGReg argreg, datalo, datahi;
3972ef6f
RH
1340 TCGMemOpIdx oi = lb->oi;
1341 TCGMemOp opc = get_memop(oi);
267c9319 1342 void *func;
df5e0ef7 1343
267c9319 1344 reloc_pc24(lb->label_ptr[0], s->code_ptr);
df5e0ef7
RH
1345
1346 argreg = tcg_out_arg_reg32(s, TCG_REG_R0, TCG_AREG0);
1347 if (TARGET_LONG_BITS == 64) {
1348 argreg = tcg_out_arg_reg64(s, argreg, lb->addrlo_reg, lb->addrhi_reg);
1349 } else {
1350 argreg = tcg_out_arg_reg32(s, argreg, lb->addrlo_reg);
1351 }
3972ef6f 1352 argreg = tcg_out_arg_imm32(s, argreg, oi);
d9f4dde4
RH
1353 argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14);
1354
1355 /* For armv6 we can use the canonical unsigned helpers and minimize
1356 icache usage. For pre-armv6, use the signed helpers since we do
1357 not have a single insn sign-extend. */
1358 if (use_armv6_instructions) {
2b7ec66f 1359 func = qemu_ld_helpers[opc & (MO_BSWAP | MO_SIZE)];
d9f4dde4 1360 } else {
2b7ec66f 1361 func = qemu_ld_helpers[opc & (MO_BSWAP | MO_SSIZE)];
099fcf2e
RH
1362 if (opc & MO_SIGN) {
1363 opc = MO_UL;
d9f4dde4
RH
1364 }
1365 }
1366 tcg_out_call(s, func);
df5e0ef7 1367
a485cff0
RH
1368 datalo = lb->datalo_reg;
1369 datahi = lb->datahi_reg;
0315c51e 1370 switch (opc & MO_SSIZE) {
099fcf2e 1371 case MO_SB:
a485cff0 1372 tcg_out_ext8s(s, COND_AL, datalo, TCG_REG_R0);
df5e0ef7 1373 break;
099fcf2e 1374 case MO_SW:
a485cff0 1375 tcg_out_ext16s(s, COND_AL, datalo, TCG_REG_R0);
df5e0ef7 1376 break;
df5e0ef7 1377 default:
a485cff0 1378 tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_R0);
df5e0ef7 1379 break;
099fcf2e 1380 case MO_Q:
a485cff0
RH
1381 if (datalo != TCG_REG_R1) {
1382 tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_R0);
1383 tcg_out_mov_reg(s, COND_AL, datahi, TCG_REG_R1);
1384 } else if (datahi != TCG_REG_R0) {
1385 tcg_out_mov_reg(s, COND_AL, datahi, TCG_REG_R1);
1386 tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_R0);
66c2056f
RH
1387 } else {
1388 tcg_out_mov_reg(s, COND_AL, TCG_REG_TMP, TCG_REG_R0);
a485cff0
RH
1389 tcg_out_mov_reg(s, COND_AL, datahi, TCG_REG_R1);
1390 tcg_out_mov_reg(s, COND_AL, datalo, TCG_REG_TMP);
66c2056f 1391 }
df5e0ef7
RH
1392 break;
1393 }
1394
267c9319 1395 tcg_out_goto(s, COND_AL, lb->raddr);
df5e0ef7
RH
1396}
1397
1398static void tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
1399{
a485cff0 1400 TCGReg argreg, datalo, datahi;
3972ef6f
RH
1401 TCGMemOpIdx oi = lb->oi;
1402 TCGMemOp opc = get_memop(oi);
df5e0ef7 1403
267c9319 1404 reloc_pc24(lb->label_ptr[0], s->code_ptr);
df5e0ef7
RH
1405
1406 argreg = TCG_REG_R0;
1407 argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
1408 if (TARGET_LONG_BITS == 64) {
1409 argreg = tcg_out_arg_reg64(s, argreg, lb->addrlo_reg, lb->addrhi_reg);
1410 } else {
1411 argreg = tcg_out_arg_reg32(s, argreg, lb->addrlo_reg);
1412 }
1413
a485cff0
RH
1414 datalo = lb->datalo_reg;
1415 datahi = lb->datahi_reg;
0315c51e 1416 switch (opc & MO_SIZE) {
099fcf2e 1417 case MO_8:
a485cff0 1418 argreg = tcg_out_arg_reg8(s, argreg, datalo);
df5e0ef7 1419 break;
099fcf2e 1420 case MO_16:
a485cff0 1421 argreg = tcg_out_arg_reg16(s, argreg, datalo);
df5e0ef7 1422 break;
099fcf2e
RH
1423 case MO_32:
1424 default:
a485cff0 1425 argreg = tcg_out_arg_reg32(s, argreg, datalo);
df5e0ef7 1426 break;
099fcf2e 1427 case MO_64:
a485cff0 1428 argreg = tcg_out_arg_reg64(s, argreg, datalo, datahi);
df5e0ef7
RH
1429 break;
1430 }
1431
3972ef6f 1432 argreg = tcg_out_arg_imm32(s, argreg, oi);
d9f4dde4 1433 argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14);
df5e0ef7 1434
d9f4dde4 1435 /* Tail-call to the helper, which will return to the fast path. */
2b7ec66f 1436 tcg_out_goto(s, COND_AL, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
df5e0ef7 1437}
cee87be8
RH
1438#endif /* SOFTMMU */
1439
091d5677
RH
1440static inline void tcg_out_qemu_ld_index(TCGContext *s, TCGMemOp opc,
1441 TCGReg datalo, TCGReg datahi,
1442 TCGReg addrlo, TCGReg addend)
cee87be8 1443{
091d5677 1444 TCGMemOp bswap = opc & MO_BSWAP;
df5e0ef7 1445
099fcf2e
RH
1446 switch (opc & MO_SSIZE) {
1447 case MO_UB:
a485cff0 1448 tcg_out_ld8_r(s, COND_AL, datalo, addrlo, addend);
811d4cf4 1449 break;
099fcf2e 1450 case MO_SB:
a485cff0 1451 tcg_out_ld8s_r(s, COND_AL, datalo, addrlo, addend);
811d4cf4 1452 break;
099fcf2e 1453 case MO_UW:
a485cff0 1454 tcg_out_ld16u_r(s, COND_AL, datalo, addrlo, addend);
67dcab73 1455 if (bswap) {
a485cff0 1456 tcg_out_bswap16(s, COND_AL, datalo, datalo);
67dcab73 1457 }
811d4cf4 1458 break;
099fcf2e 1459 case MO_SW:
67dcab73 1460 if (bswap) {
a485cff0
RH
1461 tcg_out_ld16u_r(s, COND_AL, datalo, addrlo, addend);
1462 tcg_out_bswap16s(s, COND_AL, datalo, datalo);
67dcab73 1463 } else {
a485cff0 1464 tcg_out_ld16s_r(s, COND_AL, datalo, addrlo, addend);
67dcab73 1465 }
811d4cf4 1466 break;
099fcf2e 1467 case MO_UL:
811d4cf4 1468 default:
a485cff0 1469 tcg_out_ld32_r(s, COND_AL, datalo, addrlo, addend);
67dcab73 1470 if (bswap) {
a485cff0 1471 tcg_out_bswap32(s, COND_AL, datalo, datalo);
67dcab73 1472 }
811d4cf4 1473 break;
099fcf2e 1474 case MO_Q:
66c2056f 1475 {
a485cff0
RH
1476 TCGReg dl = (bswap ? datahi : datalo);
1477 TCGReg dh = (bswap ? datalo : datahi);
66c2056f 1478
1a8e80d7
RH
1479 /* Avoid ldrd for user-only emulation, to handle unaligned. */
1480 if (USING_SOFTMMU && use_armv6_instructions
1481 && (dl & 1) == 0 && dh == dl + 1) {
a485cff0 1482 tcg_out_ldrd_r(s, COND_AL, dl, addrlo, addend);
66c2056f 1483 } else if (dl != addend) {
a485cff0 1484 tcg_out_ld32_rwb(s, COND_AL, dl, addend, addrlo);
66c2056f
RH
1485 tcg_out_ld32_12(s, COND_AL, dh, addend, 4);
1486 } else {
1487 tcg_out_dat_reg(s, COND_AL, ARITH_ADD, TCG_REG_TMP,
a485cff0 1488 addend, addrlo, SHIFT_IMM_LSL(0));
66c2056f
RH
1489 tcg_out_ld32_12(s, COND_AL, dl, TCG_REG_TMP, 0);
1490 tcg_out_ld32_12(s, COND_AL, dh, TCG_REG_TMP, 4);
1491 }
1492 if (bswap) {
66c2056f 1493 tcg_out_bswap32(s, COND_AL, dl, dl);
091d5677 1494 tcg_out_bswap32(s, COND_AL, dh, dh);
66c2056f 1495 }
67dcab73 1496 }
811d4cf4
AZ
1497 break;
1498 }
091d5677 1499}
811d4cf4 1500
091d5677
RH
1501static inline void tcg_out_qemu_ld_direct(TCGContext *s, TCGMemOp opc,
1502 TCGReg datalo, TCGReg datahi,
1503 TCGReg addrlo)
1504{
1505 TCGMemOp bswap = opc & MO_BSWAP;
379f6698 1506
099fcf2e
RH
1507 switch (opc & MO_SSIZE) {
1508 case MO_UB:
a485cff0 1509 tcg_out_ld8_12(s, COND_AL, datalo, addrlo, 0);
811d4cf4 1510 break;
099fcf2e 1511 case MO_SB:
a485cff0 1512 tcg_out_ld8s_8(s, COND_AL, datalo, addrlo, 0);
811d4cf4 1513 break;
099fcf2e 1514 case MO_UW:
a485cff0 1515 tcg_out_ld16u_8(s, COND_AL, datalo, addrlo, 0);
67dcab73 1516 if (bswap) {
a485cff0 1517 tcg_out_bswap16(s, COND_AL, datalo, datalo);
67dcab73 1518 }
811d4cf4 1519 break;
099fcf2e 1520 case MO_SW:
67dcab73 1521 if (bswap) {
a485cff0
RH
1522 tcg_out_ld16u_8(s, COND_AL, datalo, addrlo, 0);
1523 tcg_out_bswap16s(s, COND_AL, datalo, datalo);
67dcab73 1524 } else {
a485cff0 1525 tcg_out_ld16s_8(s, COND_AL, datalo, addrlo, 0);
67dcab73 1526 }
811d4cf4 1527 break;
099fcf2e 1528 case MO_UL:
811d4cf4 1529 default:
a485cff0 1530 tcg_out_ld32_12(s, COND_AL, datalo, addrlo, 0);
67dcab73 1531 if (bswap) {
a485cff0 1532 tcg_out_bswap32(s, COND_AL, datalo, datalo);
67dcab73 1533 }
811d4cf4 1534 break;
099fcf2e 1535 case MO_Q:
091d5677
RH
1536 {
1537 TCGReg dl = (bswap ? datahi : datalo);
1538 TCGReg dh = (bswap ? datalo : datahi);
1539
1a8e80d7
RH
1540 /* Avoid ldrd for user-only emulation, to handle unaligned. */
1541 if (USING_SOFTMMU && use_armv6_instructions
1542 && (dl & 1) == 0 && dh == dl + 1) {
091d5677
RH
1543 tcg_out_ldrd_8(s, COND_AL, dl, addrlo, 0);
1544 } else if (dl == addrlo) {
1545 tcg_out_ld32_12(s, COND_AL, dh, addrlo, bswap ? 0 : 4);
1546 tcg_out_ld32_12(s, COND_AL, dl, addrlo, bswap ? 4 : 0);
1547 } else {
1548 tcg_out_ld32_12(s, COND_AL, dl, addrlo, bswap ? 4 : 0);
1549 tcg_out_ld32_12(s, COND_AL, dh, addrlo, bswap ? 0 : 4);
1550 }
1551 if (bswap) {
1552 tcg_out_bswap32(s, COND_AL, dl, dl);
1553 tcg_out_bswap32(s, COND_AL, dh, dh);
1554 }
419bafa5 1555 }
811d4cf4
AZ
1556 break;
1557 }
811d4cf4
AZ
1558}
1559
091d5677 1560static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is64)
811d4cf4 1561{
15ecf6e3 1562 TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
59227d5d 1563 TCGMemOpIdx oi;
091d5677 1564 TCGMemOp opc;
811d4cf4 1565#ifdef CONFIG_SOFTMMU
099fcf2e 1566 int mem_index;
15ecf6e3 1567 TCGReg addend;
267c9319 1568 tcg_insn_unit *label_ptr;
811d4cf4 1569#endif
cee87be8 1570
a485cff0 1571 datalo = *args++;
15ecf6e3 1572 datahi = (is64 ? *args++ : 0);
a485cff0 1573 addrlo = *args++;
a485cff0 1574 addrhi = (TARGET_LONG_BITS == 64 ? *args++ : 0);
59227d5d
RH
1575 oi = *args++;
1576 opc = get_memop(oi);
811d4cf4 1577
15ecf6e3 1578#ifdef CONFIG_SOFTMMU
59227d5d 1579 mem_index = get_mmuidx(oi);
85aa8081 1580 addend = tcg_out_tlb_read(s, addrlo, addrhi, opc, mem_index, 1);
091d5677
RH
1581
1582 /* This a conditional BL only to load a pointer within this opcode into LR
1583 for the slow path. We will not be using the value for a tail call. */
1584 label_ptr = s->code_ptr;
1585 tcg_out_bl_noaddr(s, COND_NE);
1586
1587 tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, addend);
811d4cf4 1588
3972ef6f
RH
1589 add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi,
1590 s->code_ptr, label_ptr);
091d5677 1591#else /* !CONFIG_SOFTMMU */
b76f21a7
LV
1592 if (guest_base) {
1593 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, guest_base);
091d5677
RH
1594 tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, TCG_REG_TMP);
1595 } else {
1596 tcg_out_qemu_ld_direct(s, opc, datalo, datahi, addrlo);
1597 }
1598#endif
1599}
1600
1601static inline void tcg_out_qemu_st_index(TCGContext *s, int cond, TCGMemOp opc,
1602 TCGReg datalo, TCGReg datahi,
1603 TCGReg addrlo, TCGReg addend)
1604{
1605 TCGMemOp bswap = opc & MO_BSWAP;
1606
1607 switch (opc & MO_SIZE) {
099fcf2e 1608 case MO_8:
091d5677 1609 tcg_out_st8_r(s, cond, datalo, addrlo, addend);
811d4cf4 1610 break;
099fcf2e 1611 case MO_16:
67dcab73 1612 if (bswap) {
091d5677
RH
1613 tcg_out_bswap16st(s, cond, TCG_REG_R0, datalo);
1614 tcg_out_st16_r(s, cond, TCG_REG_R0, addrlo, addend);
67dcab73 1615 } else {
091d5677 1616 tcg_out_st16_r(s, cond, datalo, addrlo, addend);
67dcab73 1617 }
811d4cf4 1618 break;
099fcf2e 1619 case MO_32:
811d4cf4 1620 default:
67dcab73 1621 if (bswap) {
091d5677
RH
1622 tcg_out_bswap32(s, cond, TCG_REG_R0, datalo);
1623 tcg_out_st32_r(s, cond, TCG_REG_R0, addrlo, addend);
67dcab73 1624 } else {
091d5677 1625 tcg_out_st32_r(s, cond, datalo, addrlo, addend);
67dcab73 1626 }
811d4cf4 1627 break;
099fcf2e 1628 case MO_64:
1a8e80d7 1629 /* Avoid strd for user-only emulation, to handle unaligned. */
67dcab73 1630 if (bswap) {
091d5677
RH
1631 tcg_out_bswap32(s, cond, TCG_REG_R0, datahi);
1632 tcg_out_st32_rwb(s, cond, TCG_REG_R0, addend, addrlo);
1633 tcg_out_bswap32(s, cond, TCG_REG_R0, datalo);
1634 tcg_out_st32_12(s, cond, TCG_REG_R0, addend, 4);
1a8e80d7 1635 } else if (USING_SOFTMMU && use_armv6_instructions
a485cff0 1636 && (datalo & 1) == 0 && datahi == datalo + 1) {
091d5677 1637 tcg_out_strd_r(s, cond, datalo, addrlo, addend);
67dcab73 1638 } else {
091d5677
RH
1639 tcg_out_st32_rwb(s, cond, datalo, addend, addrlo);
1640 tcg_out_st32_12(s, cond, datahi, addend, 4);
67dcab73 1641 }
811d4cf4
AZ
1642 break;
1643 }
091d5677 1644}
811d4cf4 1645
091d5677
RH
1646static inline void tcg_out_qemu_st_direct(TCGContext *s, TCGMemOp opc,
1647 TCGReg datalo, TCGReg datahi,
1648 TCGReg addrlo)
1649{
1650 TCGMemOp bswap = opc & MO_BSWAP;
d9f4dde4 1651
091d5677 1652 switch (opc & MO_SIZE) {
099fcf2e 1653 case MO_8:
a485cff0 1654 tcg_out_st8_12(s, COND_AL, datalo, addrlo, 0);
811d4cf4 1655 break;
099fcf2e 1656 case MO_16:
67dcab73 1657 if (bswap) {
a485cff0
RH
1658 tcg_out_bswap16st(s, COND_AL, TCG_REG_R0, datalo);
1659 tcg_out_st16_8(s, COND_AL, TCG_REG_R0, addrlo, 0);
67dcab73 1660 } else {
a485cff0 1661 tcg_out_st16_8(s, COND_AL, datalo, addrlo, 0);
67dcab73 1662 }
811d4cf4 1663 break;
099fcf2e 1664 case MO_32:
811d4cf4 1665 default:
67dcab73 1666 if (bswap) {
a485cff0
RH
1667 tcg_out_bswap32(s, COND_AL, TCG_REG_R0, datalo);
1668 tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addrlo, 0);
67dcab73 1669 } else {
a485cff0 1670 tcg_out_st32_12(s, COND_AL, datalo, addrlo, 0);
67dcab73 1671 }
811d4cf4 1672 break;
099fcf2e 1673 case MO_64:
1a8e80d7 1674 /* Avoid strd for user-only emulation, to handle unaligned. */
67dcab73 1675 if (bswap) {
a485cff0
RH
1676 tcg_out_bswap32(s, COND_AL, TCG_REG_R0, datahi);
1677 tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addrlo, 0);
1678 tcg_out_bswap32(s, COND_AL, TCG_REG_R0, datalo);
1679 tcg_out_st32_12(s, COND_AL, TCG_REG_R0, addrlo, 4);
1a8e80d7 1680 } else if (USING_SOFTMMU && use_armv6_instructions
a485cff0
RH
1681 && (datalo & 1) == 0 && datahi == datalo + 1) {
1682 tcg_out_strd_8(s, COND_AL, datalo, addrlo, 0);
67dcab73 1683 } else {
a485cff0
RH
1684 tcg_out_st32_12(s, COND_AL, datalo, addrlo, 0);
1685 tcg_out_st32_12(s, COND_AL, datahi, addrlo, 4);
67dcab73 1686 }
811d4cf4
AZ
1687 break;
1688 }
091d5677
RH
1689}
1690
1691static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is64)
1692{
1693 TCGReg addrlo, datalo, datahi, addrhi __attribute__((unused));
59227d5d 1694 TCGMemOpIdx oi;
091d5677
RH
1695 TCGMemOp opc;
1696#ifdef CONFIG_SOFTMMU
1697 int mem_index;
1698 TCGReg addend;
267c9319 1699 tcg_insn_unit *label_ptr;
091d5677
RH
1700#endif
1701
1702 datalo = *args++;
1703 datahi = (is64 ? *args++ : 0);
1704 addrlo = *args++;
1705 addrhi = (TARGET_LONG_BITS == 64 ? *args++ : 0);
59227d5d
RH
1706 oi = *args++;
1707 opc = get_memop(oi);
091d5677
RH
1708
1709#ifdef CONFIG_SOFTMMU
59227d5d 1710 mem_index = get_mmuidx(oi);
85aa8081 1711 addend = tcg_out_tlb_read(s, addrlo, addrhi, opc, mem_index, 0);
091d5677
RH
1712
1713 tcg_out_qemu_st_index(s, COND_EQ, opc, datalo, datahi, addrlo, addend);
1714
1715 /* The conditional call must come last, as we're going to return here. */
1716 label_ptr = s->code_ptr;
1717 tcg_out_bl_noaddr(s, COND_NE);
1718
3972ef6f
RH
1719 add_qemu_ldst_label(s, false, oi, datalo, datahi, addrlo, addrhi,
1720 s->code_ptr, label_ptr);
091d5677 1721#else /* !CONFIG_SOFTMMU */
b76f21a7
LV
1722 if (guest_base) {
1723 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, guest_base);
091d5677
RH
1724 tcg_out_qemu_st_index(s, COND_AL, opc, datalo,
1725 datahi, addrlo, TCG_REG_TMP);
1726 } else {
1727 tcg_out_qemu_st_direct(s, opc, datalo, datahi, addrlo);
1728 }
811d4cf4
AZ
1729#endif
1730}
1731
267c9319 1732static tcg_insn_unit *tb_ret_addr;
811d4cf4 1733
a9751609 1734static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
811d4cf4
AZ
1735 const TCGArg *args, const int *const_args)
1736{
2df3f1ee 1737 TCGArg a0, a1, a2, a3, a4, a5;
811d4cf4
AZ
1738 int c;
1739
1740 switch (opc) {
1741 case INDEX_op_exit_tb:
085c648b
RH
1742 /* Reuse the zeroing that exists for goto_ptr. */
1743 a0 = args[0];
1744 if (a0 == 0) {
1745 tcg_out_goto(s, COND_AL, s->code_gen_epilogue);
1746 } else {
1747 tcg_out_movi32(s, COND_AL, TCG_REG_R0, args[0]);
1748 tcg_out_goto(s, COND_AL, tb_ret_addr);
1749 }
811d4cf4
AZ
1750 break;
1751 case INDEX_op_goto_tb:
3fb53fb4 1752 {
811d4cf4 1753 /* Indirect jump method */
308714e6
RH
1754 intptr_t ptr, dif, dil;
1755 TCGReg base = TCG_REG_PC;
1756
1757 tcg_debug_assert(s->tb_jmp_insn_offset == 0);
1758 ptr = (intptr_t)(s->tb_jmp_target_addr + args[0]);
1759 dif = ptr - ((intptr_t)s->code_ptr + 8);
1760 dil = sextract32(dif, 0, 12);
1761 if (dif != dil) {
1762 /* The TB is close, but outside the 12 bits addressable by
1763 the load. We can extend this to 20 bits with a sub of a
1764 shifted immediate from pc. In the vastly unlikely event
1765 the code requires more than 1MB, we'll use 2 insns and
1766 be no worse off. */
1767 base = TCG_REG_R0;
1768 tcg_out_movi32(s, COND_AL, base, ptr - dil);
1769 }
1770 tcg_out_ld32_12(s, COND_AL, TCG_REG_PC, base, dil);
1771 s->tb_jmp_reset_offset[args[0]] = tcg_current_code_size(s);
811d4cf4 1772 }
811d4cf4 1773 break;
085c648b
RH
1774 case INDEX_op_goto_ptr:
1775 tcg_out_bx(s, COND_AL, args[0]);
1776 break;
811d4cf4 1777 case INDEX_op_br:
bec16311 1778 tcg_out_goto_label(s, COND_AL, arg_label(args[0]));
811d4cf4
AZ
1779 break;
1780
1781 case INDEX_op_ld8u_i32:
1782 tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
1783 break;
1784 case INDEX_op_ld8s_i32:
1785 tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
1786 break;
1787 case INDEX_op_ld16u_i32:
1788 tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
1789 break;
1790 case INDEX_op_ld16s_i32:
1791 tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
1792 break;
1793 case INDEX_op_ld_i32:
1794 tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
1795 break;
1796 case INDEX_op_st8_i32:
f694a27e 1797 tcg_out_st8(s, COND_AL, args[0], args[1], args[2]);
811d4cf4
AZ
1798 break;
1799 case INDEX_op_st16_i32:
f694a27e 1800 tcg_out_st16(s, COND_AL, args[0], args[1], args[2]);
811d4cf4
AZ
1801 break;
1802 case INDEX_op_st_i32:
1803 tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
1804 break;
1805
4a1d241e
PM
1806 case INDEX_op_movcond_i32:
1807 /* Constraints mean that v2 is always in the same register as dest,
1808 * so we only need to do "if condition passed, move v1 to dest".
1809 */
5d53b4c9
RH
1810 tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
1811 args[1], args[2], const_args[2]);
1812 tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[args[5]], ARITH_MOV,
1813 ARITH_MVN, args[0], 0, args[3], const_args[3]);
4a1d241e 1814 break;
811d4cf4 1815 case INDEX_op_add_i32:
a9a86ae9
RH
1816 tcg_out_dat_rIN(s, COND_AL, ARITH_ADD, ARITH_SUB,
1817 args[0], args[1], args[2], const_args[2]);
1818 break;
811d4cf4 1819 case INDEX_op_sub_i32:
d9fda575
RH
1820 if (const_args[1]) {
1821 if (const_args[2]) {
1822 tcg_out_movi32(s, COND_AL, args[0], args[1] - args[2]);
1823 } else {
1824 tcg_out_dat_rI(s, COND_AL, ARITH_RSB,
1825 args[0], args[2], args[1], 1);
1826 }
1827 } else {
1828 tcg_out_dat_rIN(s, COND_AL, ARITH_SUB, ARITH_ADD,
1829 args[0], args[1], args[2], const_args[2]);
1830 }
a9a86ae9 1831 break;
811d4cf4 1832 case INDEX_op_and_i32:
19b62bf4
RH
1833 tcg_out_dat_rIK(s, COND_AL, ARITH_AND, ARITH_BIC,
1834 args[0], args[1], args[2], const_args[2]);
1835 break;
932234f6 1836 case INDEX_op_andc_i32:
19b62bf4
RH
1837 tcg_out_dat_rIK(s, COND_AL, ARITH_BIC, ARITH_AND,
1838 args[0], args[1], args[2], const_args[2]);
1839 break;
811d4cf4
AZ
1840 case INDEX_op_or_i32:
1841 c = ARITH_ORR;
1842 goto gen_arith;
1843 case INDEX_op_xor_i32:
1844 c = ARITH_EOR;
1845 /* Fall through. */
1846 gen_arith:
7fc645bf 1847 tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]);
811d4cf4
AZ
1848 break;
1849 case INDEX_op_add2_i32:
2df3f1ee
RH
1850 a0 = args[0], a1 = args[1], a2 = args[2];
1851 a3 = args[3], a4 = args[4], a5 = args[5];
1852 if (a0 == a3 || (a0 == a5 && !const_args[5])) {
4346457a 1853 a0 = TCG_REG_TMP;
2df3f1ee
RH
1854 }
1855 tcg_out_dat_rIN(s, COND_AL, ARITH_ADD | TO_CPSR, ARITH_SUB | TO_CPSR,
1856 a0, a2, a4, const_args[4]);
1857 tcg_out_dat_rIK(s, COND_AL, ARITH_ADC, ARITH_SBC,
1858 a1, a3, a5, const_args[5]);
1859 tcg_out_mov_reg(s, COND_AL, args[0], a0);
811d4cf4
AZ
1860 break;
1861 case INDEX_op_sub2_i32:
2df3f1ee
RH
1862 a0 = args[0], a1 = args[1], a2 = args[2];
1863 a3 = args[3], a4 = args[4], a5 = args[5];
1864 if ((a0 == a3 && !const_args[3]) || (a0 == a5 && !const_args[5])) {
4346457a 1865 a0 = TCG_REG_TMP;
2df3f1ee
RH
1866 }
1867 if (const_args[2]) {
1868 if (const_args[4]) {
1869 tcg_out_movi32(s, COND_AL, a0, a4);
1870 a4 = a0;
1871 }
1872 tcg_out_dat_rI(s, COND_AL, ARITH_RSB | TO_CPSR, a0, a4, a2, 1);
1873 } else {
1874 tcg_out_dat_rIN(s, COND_AL, ARITH_SUB | TO_CPSR,
1875 ARITH_ADD | TO_CPSR, a0, a2, a4, const_args[4]);
1876 }
1877 if (const_args[3]) {
1878 if (const_args[5]) {
1879 tcg_out_movi32(s, COND_AL, a1, a5);
1880 a5 = a1;
1881 }
1882 tcg_out_dat_rI(s, COND_AL, ARITH_RSC, a1, a5, a3, 1);
1883 } else {
1884 tcg_out_dat_rIK(s, COND_AL, ARITH_SBC, ARITH_ADC,
1885 a1, a3, a5, const_args[5]);
1886 }
1887 tcg_out_mov_reg(s, COND_AL, args[0], a0);
811d4cf4 1888 break;
650bbb36
AZ
1889 case INDEX_op_neg_i32:
1890 tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
1891 break;
f878d2d2
LD
1892 case INDEX_op_not_i32:
1893 tcg_out_dat_reg(s, COND_AL,
1894 ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0));
1895 break;
811d4cf4
AZ
1896 case INDEX_op_mul_i32:
1897 tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
1898 break;
1899 case INDEX_op_mulu2_i32:
1900 tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
1901 break;
d693e147
RH
1902 case INDEX_op_muls2_i32:
1903 tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]);
1904 break;
811d4cf4
AZ
1905 /* XXX: Perhaps args[2] & 0x1f is wrong */
1906 case INDEX_op_shl_i32:
1907 c = const_args[2] ?
1908 SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
1909 goto gen_shift32;
1910 case INDEX_op_shr_i32:
1911 c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
1912 SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
1913 goto gen_shift32;
1914 case INDEX_op_sar_i32:
1915 c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
1916 SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
293579e5
AJ
1917 goto gen_shift32;
1918 case INDEX_op_rotr_i32:
1919 c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) :
1920 SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]);
811d4cf4
AZ
1921 /* Fall through. */
1922 gen_shift32:
1923 tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
1924 break;
1925
293579e5
AJ
1926 case INDEX_op_rotl_i32:
1927 if (const_args[2]) {
1928 tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
1929 ((0x20 - args[2]) & 0x1f) ?
1930 SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) :
1931 SHIFT_IMM_LSL(0));
1932 } else {
7a3a0097 1933 tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_TMP, args[2], 0x20);
293579e5 1934 tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1],
4346457a 1935 SHIFT_REG_ROR(TCG_REG_TMP));
293579e5
AJ
1936 }
1937 break;
1938
cc0fec8a
RH
1939 case INDEX_op_ctz_i32:
1940 tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0);
1941 a1 = TCG_REG_TMP;
1942 goto do_clz;
1943
1944 case INDEX_op_clz_i32:
1945 a1 = args[1];
1946 do_clz:
1947 a0 = args[0];
1948 a2 = args[2];
1949 c = const_args[2];
1950 if (c && a2 == 32) {
1951 tcg_out_dat_reg(s, COND_AL, INSN_CLZ, a0, 0, a1, 0);
1952 break;
1953 }
1954 tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0);
1955 tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0);
1956 if (c || a0 != a2) {
1957 tcg_out_dat_rIK(s, COND_EQ, ARITH_MOV, ARITH_MVN, a0, 0, a2, c);
1958 }
1959 break;
1960
811d4cf4 1961 case INDEX_op_brcond_i32:
5d53b4c9 1962 tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
7fc645bf 1963 args[0], args[1], const_args[1]);
bec16311
RH
1964 tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]],
1965 arg_label(args[3]));
811d4cf4
AZ
1966 break;
1967 case INDEX_op_brcond2_i32:
1968 /* The resulting conditions are:
1969 * TCG_COND_EQ --> a0 == a2 && a1 == a3,
1970 * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
1971 * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
1972 * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
1973 * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
1974 * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
1975 */
5d53b4c9
RH
1976 tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
1977 args[1], args[3], const_args[3]);
1978 tcg_out_dat_rIN(s, COND_EQ, ARITH_CMP, ARITH_CMN, 0,
1979 args[0], args[2], const_args[2]);
bec16311
RH
1980 tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]],
1981 arg_label(args[5]));
811d4cf4 1982 break;
f72a6cd7 1983 case INDEX_op_setcond_i32:
5d53b4c9
RH
1984 tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
1985 args[1], args[2], const_args[2]);
f72a6cd7
AJ
1986 tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[3]],
1987 ARITH_MOV, args[0], 0, 1);
1988 tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[3])],
1989 ARITH_MOV, args[0], 0, 0);
1990 break;
e0404769
AJ
1991 case INDEX_op_setcond2_i32:
1992 /* See brcond2_i32 comment */
5d53b4c9
RH
1993 tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0,
1994 args[2], args[4], const_args[4]);
1995 tcg_out_dat_rIN(s, COND_EQ, ARITH_CMP, ARITH_CMN, 0,
1996 args[1], args[3], const_args[3]);
e0404769
AJ
1997 tcg_out_dat_imm(s, tcg_cond_to_arm_cond[args[5]],
1998 ARITH_MOV, args[0], 0, 1);
1999 tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(args[5])],
2000 ARITH_MOV, args[0], 0, 0);
b525f0a9 2001 break;
811d4cf4 2002
15ecf6e3
RH
2003 case INDEX_op_qemu_ld_i32:
2004 tcg_out_qemu_ld(s, args, 0);
811d4cf4 2005 break;
15ecf6e3
RH
2006 case INDEX_op_qemu_ld_i64:
2007 tcg_out_qemu_ld(s, args, 1);
811d4cf4 2008 break;
15ecf6e3
RH
2009 case INDEX_op_qemu_st_i32:
2010 tcg_out_qemu_st(s, args, 0);
811d4cf4 2011 break;
15ecf6e3
RH
2012 case INDEX_op_qemu_st_i64:
2013 tcg_out_qemu_st(s, args, 1);
811d4cf4
AZ
2014 break;
2015
244b1e81
AJ
2016 case INDEX_op_bswap16_i32:
2017 tcg_out_bswap16(s, COND_AL, args[0], args[1]);
2018 break;
2019 case INDEX_op_bswap32_i32:
2020 tcg_out_bswap32(s, COND_AL, args[0], args[1]);
2021 break;
2022
811d4cf4 2023 case INDEX_op_ext8s_i32:
9517094f 2024 tcg_out_ext8s(s, COND_AL, args[0], args[1]);
811d4cf4
AZ
2025 break;
2026 case INDEX_op_ext16s_i32:
9517094f
AJ
2027 tcg_out_ext16s(s, COND_AL, args[0], args[1]);
2028 break;
2029 case INDEX_op_ext16u_i32:
2030 tcg_out_ext16u(s, COND_AL, args[0], args[1]);
811d4cf4
AZ
2031 break;
2032
b6b24cb0
RH
2033 case INDEX_op_deposit_i32:
2034 tcg_out_deposit(s, COND_AL, args[0], args[2],
2035 args[3], args[4], const_args[2]);
2036 break;
ec903af1
RH
2037 case INDEX_op_extract_i32:
2038 tcg_out_extract(s, COND_AL, args[0], args[1], args[2], args[3]);
2039 break;
2040 case INDEX_op_sextract_i32:
2041 tcg_out_sextract(s, COND_AL, args[0], args[1], args[2], args[3]);
2042 break;
b6b24cb0 2043
0637c56c
RH
2044 case INDEX_op_div_i32:
2045 tcg_out_sdiv(s, COND_AL, args[0], args[1], args[2]);
2046 break;
2047 case INDEX_op_divu_i32:
2048 tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]);
2049 break;
0637c56c 2050
40f191ab
PK
2051 case INDEX_op_mb:
2052 tcg_out_mb(s, args[0]);
2053 break;
2054
96d0ee7f
RH
2055 case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */
2056 case INDEX_op_movi_i32: /* Always emitted via tcg_out_movi. */
2057 case INDEX_op_call: /* Always emitted via tcg_out_call. */
811d4cf4
AZ
2058 default:
2059 tcg_abort();
2060 }
2061}
2062
2063static const TCGTargetOpDef arm_op_defs[] = {
2064 { INDEX_op_exit_tb, { } },
2065 { INDEX_op_goto_tb, { } },
811d4cf4 2066 { INDEX_op_br, { } },
085c648b 2067 { INDEX_op_goto_ptr, { "r" } },
811d4cf4 2068
811d4cf4
AZ
2069 { INDEX_op_ld8u_i32, { "r", "r" } },
2070 { INDEX_op_ld8s_i32, { "r", "r" } },
2071 { INDEX_op_ld16u_i32, { "r", "r" } },
2072 { INDEX_op_ld16s_i32, { "r", "r" } },
2073 { INDEX_op_ld_i32, { "r", "r" } },
2074 { INDEX_op_st8_i32, { "r", "r" } },
2075 { INDEX_op_st16_i32, { "r", "r" } },
2076 { INDEX_op_st_i32, { "r", "r" } },
2077
2078 /* TODO: "r", "r", "ri" */
a9a86ae9 2079 { INDEX_op_add_i32, { "r", "r", "rIN" } },
d9fda575 2080 { INDEX_op_sub_i32, { "r", "rI", "rIN" } },
811d4cf4
AZ
2081 { INDEX_op_mul_i32, { "r", "r", "r" } },
2082 { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
d693e147 2083 { INDEX_op_muls2_i32, { "r", "r", "r", "r" } },
19b62bf4
RH
2084 { INDEX_op_and_i32, { "r", "r", "rIK" } },
2085 { INDEX_op_andc_i32, { "r", "r", "rIK" } },
cb4e581f
LD
2086 { INDEX_op_or_i32, { "r", "r", "rI" } },
2087 { INDEX_op_xor_i32, { "r", "r", "rI" } },
650bbb36 2088 { INDEX_op_neg_i32, { "r", "r" } },
f878d2d2 2089 { INDEX_op_not_i32, { "r", "r" } },
811d4cf4
AZ
2090
2091 { INDEX_op_shl_i32, { "r", "r", "ri" } },
2092 { INDEX_op_shr_i32, { "r", "r", "ri" } },
2093 { INDEX_op_sar_i32, { "r", "r", "ri" } },
293579e5
AJ
2094 { INDEX_op_rotl_i32, { "r", "r", "ri" } },
2095 { INDEX_op_rotr_i32, { "r", "r", "ri" } },
cc0fec8a
RH
2096 { INDEX_op_clz_i32, { "r", "r", "rIK" } },
2097 { INDEX_op_ctz_i32, { "r", "r", "rIK" } },
811d4cf4 2098
5d53b4c9
RH
2099 { INDEX_op_brcond_i32, { "r", "rIN" } },
2100 { INDEX_op_setcond_i32, { "r", "r", "rIN" } },
2101 { INDEX_op_movcond_i32, { "r", "r", "rIN", "rIK", "0" } },
811d4cf4 2102
2df3f1ee
RH
2103 { INDEX_op_add2_i32, { "r", "r", "r", "r", "rIN", "rIK" } },
2104 { INDEX_op_sub2_i32, { "r", "r", "rI", "rI", "rIN", "rIK" } },
5d53b4c9
RH
2105 { INDEX_op_brcond2_i32, { "r", "r", "rIN", "rIN" } },
2106 { INDEX_op_setcond2_i32, { "r", "r", "r", "rIN", "rIN" } },
811d4cf4 2107
26c5d372 2108#if TARGET_LONG_BITS == 32
15ecf6e3
RH
2109 { INDEX_op_qemu_ld_i32, { "r", "l" } },
2110 { INDEX_op_qemu_ld_i64, { "r", "r", "l" } },
2111 { INDEX_op_qemu_st_i32, { "s", "s" } },
2112 { INDEX_op_qemu_st_i64, { "s", "s", "s" } },
26c5d372 2113#else
15ecf6e3
RH
2114 { INDEX_op_qemu_ld_i32, { "r", "l", "l" } },
2115 { INDEX_op_qemu_ld_i64, { "r", "r", "l", "l" } },
2116 { INDEX_op_qemu_st_i32, { "s", "s", "s" } },
2117 { INDEX_op_qemu_st_i64, { "s", "s", "s", "s" } },
26c5d372 2118#endif
811d4cf4 2119
244b1e81
AJ
2120 { INDEX_op_bswap16_i32, { "r", "r" } },
2121 { INDEX_op_bswap32_i32, { "r", "r" } },
2122
811d4cf4
AZ
2123 { INDEX_op_ext8s_i32, { "r", "r" } },
2124 { INDEX_op_ext16s_i32, { "r", "r" } },
9517094f 2125 { INDEX_op_ext16u_i32, { "r", "r" } },
811d4cf4 2126
b6b24cb0 2127 { INDEX_op_deposit_i32, { "r", "0", "rZ" } },
ec903af1
RH
2128 { INDEX_op_extract_i32, { "r", "r" } },
2129 { INDEX_op_sextract_i32, { "r", "r" } },
b6b24cb0 2130
0637c56c 2131 { INDEX_op_div_i32, { "r", "r", "r" } },
0637c56c 2132 { INDEX_op_divu_i32, { "r", "r", "r" } },
0637c56c 2133
40f191ab 2134 { INDEX_op_mb, { } },
811d4cf4
AZ
2135 { -1 },
2136};
2137
f69d277e
RH
2138static const TCGTargetOpDef *tcg_target_op_def(TCGOpcode op)
2139{
2140 int i, n = ARRAY_SIZE(arm_op_defs);
2141
2142 for (i = 0; i < n; ++i) {
2143 if (arm_op_defs[i].op == op) {
2144 return &arm_op_defs[i];
2145 }
2146 }
2147 return NULL;
2148}
2149
e4d58b41 2150static void tcg_target_init(TCGContext *s)
811d4cf4 2151{
1e709f38
RH
2152 /* Only probe for the platform and capabilities if we havn't already
2153 determined maximum values at compile time. */
41d9ea80 2154#ifndef use_idiv_instructions
72e1ccfc 2155 {
41d9ea80 2156 unsigned long hwcap = qemu_getauxval(AT_HWCAP);
72e1ccfc
RH
2157 use_idiv_instructions = (hwcap & HWCAP_ARM_IDIVA) != 0;
2158 }
41d9ea80 2159#endif
1e709f38 2160 if (__ARM_ARCH < 7) {
41d9ea80 2161 const char *pl = (const char *)qemu_getauxval(AT_PLATFORM);
1e709f38
RH
2162 if (pl != NULL && pl[0] == 'v' && pl[1] >= '4' && pl[1] <= '9') {
2163 arm_arch = pl[1] - '0';
2164 }
2165 }
72e1ccfc 2166
f46934df
RH
2167 tcg_target_available_regs[TCG_TYPE_I32] = 0xffff;
2168
2169 tcg_target_call_clobber_regs = 0;
2170 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R0);
2171 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R1);
2172 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R2);
2173 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R3);
2174 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R12);
2175 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_R14);
811d4cf4 2176
ccb1bb66 2177 s->reserved_regs = 0;
811d4cf4 2178 tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
4346457a 2179 tcg_regset_set_reg(s->reserved_regs, TCG_REG_TMP);
e4a7d5e8 2180 tcg_regset_set_reg(s->reserved_regs, TCG_REG_PC);
811d4cf4
AZ
2181}
2182
2a534aff 2183static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg arg,
a05b5b9b 2184 TCGReg arg1, intptr_t arg2)
811d4cf4
AZ
2185{
2186 tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
2187}
2188
2a534aff 2189static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg,
a05b5b9b 2190 TCGReg arg1, intptr_t arg2)
811d4cf4
AZ
2191{
2192 tcg_out_st32(s, COND_AL, arg, arg1, arg2);
2193}
2194
59d7c14e
RH
2195static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val,
2196 TCGReg base, intptr_t ofs)
2197{
2198 return false;
2199}
2200
2a534aff
RH
2201static inline void tcg_out_mov(TCGContext *s, TCGType type,
2202 TCGReg ret, TCGReg arg)
811d4cf4
AZ
2203{
2204 tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
2205}
2206
2207static inline void tcg_out_movi(TCGContext *s, TCGType type,
2a534aff 2208 TCGReg ret, tcg_target_long arg)
811d4cf4
AZ
2209{
2210 tcg_out_movi32(s, COND_AL, ret, arg);
2211}
2212
880ad962
RH
2213static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
2214{
2215 int i;
2216 for (i = 0; i < count; ++i) {
2217 p[i] = INSN_NOP;
2218 }
2219}
2220
0caa91fe
RH
2221/* Compute frame size via macros, to share between tcg_target_qemu_prologue
2222 and tcg_register_jit. */
2223
2224#define PUSH_SIZE ((11 - 4 + 1 + 1) * sizeof(tcg_target_long))
2225
2226#define FRAME_SIZE \
2227 ((PUSH_SIZE \
2228 + TCG_STATIC_CALL_ARGS_SIZE \
2229 + CPU_TEMP_BUF_NLONGS * sizeof(long) \
2230 + TCG_TARGET_STACK_ALIGN - 1) \
2231 & -TCG_TARGET_STACK_ALIGN)
2232
e4d58b41 2233static void tcg_target_qemu_prologue(TCGContext *s)
811d4cf4 2234{
0caa91fe 2235 int stack_addend;
fc4d60ee
RH
2236
2237 /* Calling convention requires us to save r4-r11 and lr. */
2238 /* stmdb sp!, { r4 - r11, lr } */
2239 tcg_out32(s, (COND_AL << 28) | 0x092d4ff0);
cea5f9a2 2240
0caa91fe
RH
2241 /* Reserve callee argument and tcg temp space. */
2242 stack_addend = FRAME_SIZE - PUSH_SIZE;
fc4d60ee
RH
2243
2244 tcg_out_dat_rI(s, COND_AL, ARITH_SUB, TCG_REG_CALL_STACK,
0caa91fe 2245 TCG_REG_CALL_STACK, stack_addend, 1);
fc4d60ee
RH
2246 tcg_set_frame(s, TCG_REG_CALL_STACK, TCG_STATIC_CALL_ARGS_SIZE,
2247 CPU_TEMP_BUF_NLONGS * sizeof(long));
4e17eae9 2248
cea5f9a2 2249 tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
811d4cf4 2250
cea5f9a2 2251 tcg_out_bx(s, COND_AL, tcg_target_call_iarg_regs[1]);
811d4cf4 2252
085c648b
RH
2253 /*
2254 * Return path for goto_ptr. Set return value to 0, a-la exit_tb,
2255 * and fall through to the rest of the epilogue.
2256 */
2257 s->code_gen_epilogue = s->code_ptr;
2258 tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R0, 0);
2259
2260 /* TB epilogue */
2261 tb_ret_addr = s->code_ptr;
fc4d60ee 2262 tcg_out_dat_rI(s, COND_AL, ARITH_ADD, TCG_REG_CALL_STACK,
0caa91fe 2263 TCG_REG_CALL_STACK, stack_addend, 1);
fc4d60ee
RH
2264
2265 /* ldmia sp!, { r4 - r11, pc } */
2266 tcg_out32(s, (COND_AL << 28) | 0x08bd8ff0);
811d4cf4 2267}
0caa91fe
RH
2268
2269typedef struct {
16959741 2270 DebugFrameHeader h;
0caa91fe
RH
2271 uint8_t fde_def_cfa[4];
2272 uint8_t fde_reg_ofs[18];
2273} DebugFrame;
2274
2275#define ELF_HOST_MACHINE EM_ARM
2276
2277/* We're expecting a 2 byte uleb128 encoded value. */
2278QEMU_BUILD_BUG_ON(FRAME_SIZE >= (1 << 14));
2279
16959741
RH
2280static const DebugFrame debug_frame = {
2281 .h.cie.len = sizeof(DebugFrameCIE)-4, /* length after .len member */
2282 .h.cie.id = -1,
2283 .h.cie.version = 1,
2284 .h.cie.code_align = 1,
2285 .h.cie.data_align = 0x7c, /* sleb128 -4 */
2286 .h.cie.return_column = 14,
0caa91fe
RH
2287
2288 /* Total FDE size does not include the "len" member. */
16959741 2289 .h.fde.len = sizeof(DebugFrame) - offsetof(DebugFrame, h.fde.cie_offset),
0caa91fe
RH
2290
2291 .fde_def_cfa = {
2292 12, 13, /* DW_CFA_def_cfa sp, ... */
2293 (FRAME_SIZE & 0x7f) | 0x80, /* ... uleb128 FRAME_SIZE */
2294 (FRAME_SIZE >> 7)
2295 },
2296 .fde_reg_ofs = {
2297 /* The following must match the stmdb in the prologue. */
2298 0x8e, 1, /* DW_CFA_offset, lr, -4 */
2299 0x8b, 2, /* DW_CFA_offset, r11, -8 */
2300 0x8a, 3, /* DW_CFA_offset, r10, -12 */
2301 0x89, 4, /* DW_CFA_offset, r9, -16 */
2302 0x88, 5, /* DW_CFA_offset, r8, -20 */
2303 0x87, 6, /* DW_CFA_offset, r7, -24 */
2304 0x86, 7, /* DW_CFA_offset, r6, -28 */
2305 0x85, 8, /* DW_CFA_offset, r5, -32 */
2306 0x84, 9, /* DW_CFA_offset, r4, -36 */
2307 }
2308};
2309
2310void tcg_register_jit(void *buf, size_t buf_size)
2311{
0caa91fe
RH
2312 tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame));
2313}