2 * Tiny Code Generator for QEMU
4 * Copyright (c) 2008 Andrzej Zaborowski
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
25 #if defined(__ARM_ARCH_7__) || \
26 defined(__ARM_ARCH_7A__) || \
27 defined(__ARM_ARCH_7EM__) || \
28 defined(__ARM_ARCH_7M__) || \
29 defined(__ARM_ARCH_7R__)
30 #define USE_ARMV7_INSTRUCTIONS
33 #if defined(USE_ARMV7_INSTRUCTIONS) || \
34 defined(__ARM_ARCH_6J__) || \
35 defined(__ARM_ARCH_6K__) || \
36 defined(__ARM_ARCH_6T2__) || \
37 defined(__ARM_ARCH_6Z__) || \
38 defined(__ARM_ARCH_6ZK__)
39 #define USE_ARMV6_INSTRUCTIONS
42 #if defined(USE_ARMV6_INSTRUCTIONS) || \
43 defined(__ARM_ARCH_5T__) || \
44 defined(__ARM_ARCH_5TE__) || \
45 defined(__ARM_ARCH_5TEJ__)
46 #define USE_ARMV5_INSTRUCTIONS
49 #ifdef USE_ARMV5_INSTRUCTIONS
50 static const int use_armv5_instructions
= 1;
52 static const int use_armv5_instructions
= 0;
54 #undef USE_ARMV5_INSTRUCTIONS
56 #ifdef USE_ARMV6_INSTRUCTIONS
57 static const int use_armv6_instructions
= 1;
59 static const int use_armv6_instructions
= 0;
61 #undef USE_ARMV6_INSTRUCTIONS
63 #ifdef USE_ARMV7_INSTRUCTIONS
64 static const int use_armv7_instructions
= 1;
66 static const int use_armv7_instructions
= 0;
68 #undef USE_ARMV7_INSTRUCTIONS
70 #ifndef use_idiv_instructions
71 bool use_idiv_instructions
;
73 #ifdef CONFIG_GETAUXVAL
74 # include <sys/auxv.h>
78 static const char * const tcg_target_reg_names
[TCG_TARGET_NB_REGS
] = {
98 static const int tcg_target_reg_alloc_order
[] = {
116 static const int tcg_target_call_iarg_regs
[4] = {
117 TCG_REG_R0
, TCG_REG_R1
, TCG_REG_R2
, TCG_REG_R3
119 static const int tcg_target_call_oarg_regs
[2] = {
120 TCG_REG_R0
, TCG_REG_R1
123 #define TCG_REG_TMP TCG_REG_R12
125 static inline void reloc_abs32(void *code_ptr
, tcg_target_long target
)
127 *(uint32_t *) code_ptr
= target
;
130 static inline void reloc_pc24(void *code_ptr
, tcg_target_long target
)
132 uint32_t offset
= ((target
- ((tcg_target_long
) code_ptr
+ 8)) >> 2);
134 *(uint32_t *) code_ptr
= ((*(uint32_t *) code_ptr
) & ~0xffffff)
135 | (offset
& 0xffffff);
138 static void patch_reloc(uint8_t *code_ptr
, int type
,
139 tcg_target_long value
, tcg_target_long addend
)
143 reloc_abs32(code_ptr
, value
);
152 reloc_pc24(code_ptr
, value
);
157 #define TCG_CT_CONST_ARM 0x100
158 #define TCG_CT_CONST_INV 0x200
159 #define TCG_CT_CONST_NEG 0x400
160 #define TCG_CT_CONST_ZERO 0x800
162 /* parse target specific constraints */
163 static int target_parse_constraint(TCGArgConstraint
*ct
, const char **pct_str
)
170 ct
->ct
|= TCG_CT_CONST_ARM
;
173 ct
->ct
|= TCG_CT_CONST_INV
;
175 case 'N': /* The gcc constraint letter is L, already used here. */
176 ct
->ct
|= TCG_CT_CONST_NEG
;
179 ct
->ct
|= TCG_CT_CONST_ZERO
;
183 ct
->ct
|= TCG_CT_REG
;
184 tcg_regset_set32(ct
->u
.regs
, 0, (1 << TCG_TARGET_NB_REGS
) - 1);
187 /* qemu_ld address */
189 ct
->ct
|= TCG_CT_REG
;
190 tcg_regset_set32(ct
->u
.regs
, 0, (1 << TCG_TARGET_NB_REGS
) - 1);
191 #ifdef CONFIG_SOFTMMU
192 /* r0-r2 will be overwritten when reading the tlb entry,
193 so don't use these. */
194 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R0
);
195 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R1
);
196 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R2
);
200 ct
->ct
|= TCG_CT_REG
;
201 tcg_regset_set32(ct
->u
.regs
, 0, (1 << TCG_TARGET_NB_REGS
) - 1);
202 #ifdef CONFIG_SOFTMMU
203 /* r1 is still needed to load data_reg or data_reg2,
205 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R1
);
209 /* qemu_st address & data_reg */
211 ct
->ct
|= TCG_CT_REG
;
212 tcg_regset_set32(ct
->u
.regs
, 0, (1 << TCG_TARGET_NB_REGS
) - 1);
213 /* r0-r2 will be overwritten when reading the tlb entry (softmmu only)
214 and r0-r1 doing the byte swapping, so don't use these. */
215 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R0
);
216 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R1
);
217 #if defined(CONFIG_SOFTMMU)
218 /* Avoid clashes with registers being used for helper args */
219 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R2
);
220 #if TARGET_LONG_BITS == 64
221 /* Avoid clashes with registers being used for helper args */
222 tcg_regset_reset_reg(ct
->u
.regs
, TCG_REG_R3
);
236 static inline uint32_t rotl(uint32_t val
, int n
)
238 return (val
<< n
) | (val
>> (32 - n
));
241 /* ARM immediates for ALU instructions are made of an unsigned 8-bit
242 right-rotated by an even amount between 0 and 30. */
243 static inline int encode_imm(uint32_t imm
)
247 /* simple case, only lower bits */
248 if ((imm
& ~0xff) == 0)
250 /* then try a simple even shift */
251 shift
= ctz32(imm
) & ~1;
252 if (((imm
>> shift
) & ~0xff) == 0)
254 /* now try harder with rotations */
255 if ((rotl(imm
, 2) & ~0xff) == 0)
257 if ((rotl(imm
, 4) & ~0xff) == 0)
259 if ((rotl(imm
, 6) & ~0xff) == 0)
261 /* imm can't be encoded */
265 static inline int check_fit_imm(uint32_t imm
)
267 return encode_imm(imm
) >= 0;
270 /* Test if a constant matches the constraint.
271 * TODO: define constraints for:
273 * ldr/str offset: between -0xfff and 0xfff
274 * ldrh/strh offset: between -0xff and 0xff
275 * mov operand2: values represented with x << (2 * y), x < 0x100
276 * add, sub, eor...: ditto
278 static inline int tcg_target_const_match(tcg_target_long val
,
279 const TCGArgConstraint
*arg_ct
)
283 if (ct
& TCG_CT_CONST
) {
285 } else if ((ct
& TCG_CT_CONST_ARM
) && check_fit_imm(val
)) {
287 } else if ((ct
& TCG_CT_CONST_INV
) && check_fit_imm(~val
)) {
289 } else if ((ct
& TCG_CT_CONST_NEG
) && check_fit_imm(-val
)) {
291 } else if ((ct
& TCG_CT_CONST_ZERO
) && val
== 0) {
298 #define TO_CPSR (1 << 20)
301 ARITH_AND
= 0x0 << 21,
302 ARITH_EOR
= 0x1 << 21,
303 ARITH_SUB
= 0x2 << 21,
304 ARITH_RSB
= 0x3 << 21,
305 ARITH_ADD
= 0x4 << 21,
306 ARITH_ADC
= 0x5 << 21,
307 ARITH_SBC
= 0x6 << 21,
308 ARITH_RSC
= 0x7 << 21,
309 ARITH_TST
= 0x8 << 21 | TO_CPSR
,
310 ARITH_CMP
= 0xa << 21 | TO_CPSR
,
311 ARITH_CMN
= 0xb << 21 | TO_CPSR
,
312 ARITH_ORR
= 0xc << 21,
313 ARITH_MOV
= 0xd << 21,
314 ARITH_BIC
= 0xe << 21,
315 ARITH_MVN
= 0xf << 21,
317 INSN_LDR_IMM
= 0x04100000,
318 INSN_LDR_REG
= 0x06100000,
319 INSN_STR_IMM
= 0x04000000,
320 INSN_STR_REG
= 0x06000000,
322 INSN_LDRH_IMM
= 0x005000b0,
323 INSN_LDRH_REG
= 0x001000b0,
324 INSN_LDRSH_IMM
= 0x005000f0,
325 INSN_LDRSH_REG
= 0x001000f0,
326 INSN_STRH_IMM
= 0x004000b0,
327 INSN_STRH_REG
= 0x000000b0,
329 INSN_LDRB_IMM
= 0x04500000,
330 INSN_LDRB_REG
= 0x06500000,
331 INSN_LDRSB_IMM
= 0x005000d0,
332 INSN_LDRSB_REG
= 0x001000d0,
333 INSN_STRB_IMM
= 0x04400000,
334 INSN_STRB_REG
= 0x06400000,
336 INSN_LDRD_IMM
= 0x004000d0,
339 #define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00)
340 #define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20)
341 #define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40)
342 #define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60)
343 #define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10)
344 #define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30)
345 #define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50)
346 #define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70)
348 enum arm_cond_code_e
{
351 COND_CS
= 0x2, /* Unsigned greater or equal */
352 COND_CC
= 0x3, /* Unsigned less than */
353 COND_MI
= 0x4, /* Negative */
354 COND_PL
= 0x5, /* Zero or greater */
355 COND_VS
= 0x6, /* Overflow */
356 COND_VC
= 0x7, /* No overflow */
357 COND_HI
= 0x8, /* Unsigned greater than */
358 COND_LS
= 0x9, /* Unsigned less or equal */
366 static const uint8_t tcg_cond_to_arm_cond
[] = {
367 [TCG_COND_EQ
] = COND_EQ
,
368 [TCG_COND_NE
] = COND_NE
,
369 [TCG_COND_LT
] = COND_LT
,
370 [TCG_COND_GE
] = COND_GE
,
371 [TCG_COND_LE
] = COND_LE
,
372 [TCG_COND_GT
] = COND_GT
,
374 [TCG_COND_LTU
] = COND_CC
,
375 [TCG_COND_GEU
] = COND_CS
,
376 [TCG_COND_LEU
] = COND_LS
,
377 [TCG_COND_GTU
] = COND_HI
,
380 static inline void tcg_out_bx(TCGContext
*s
, int cond
, int rn
)
382 tcg_out32(s
, (cond
<< 28) | 0x012fff10 | rn
);
385 static inline void tcg_out_b(TCGContext
*s
, int cond
, int32_t offset
)
387 tcg_out32(s
, (cond
<< 28) | 0x0a000000 |
388 (((offset
- 8) >> 2) & 0x00ffffff));
391 static inline void tcg_out_b_noaddr(TCGContext
*s
, int cond
)
393 /* We pay attention here to not modify the branch target by skipping
394 the corresponding bytes. This ensure that caches and memory are
395 kept coherent during retranslation. */
396 #ifdef HOST_WORDS_BIGENDIAN
397 tcg_out8(s
, (cond
<< 4) | 0x0a);
401 tcg_out8(s
, (cond
<< 4) | 0x0a);
405 static inline void tcg_out_bl(TCGContext
*s
, int cond
, int32_t offset
)
407 tcg_out32(s
, (cond
<< 28) | 0x0b000000 |
408 (((offset
- 8) >> 2) & 0x00ffffff));
411 static inline void tcg_out_blx(TCGContext
*s
, int cond
, int rn
)
413 tcg_out32(s
, (cond
<< 28) | 0x012fff30 | rn
);
416 static inline void tcg_out_blx_imm(TCGContext
*s
, int32_t offset
)
418 tcg_out32(s
, 0xfa000000 | ((offset
& 2) << 23) |
419 (((offset
- 8) >> 2) & 0x00ffffff));
422 static inline void tcg_out_dat_reg(TCGContext
*s
,
423 int cond
, int opc
, int rd
, int rn
, int rm
, int shift
)
425 tcg_out32(s
, (cond
<< 28) | (0 << 25) | opc
|
426 (rn
<< 16) | (rd
<< 12) | shift
| rm
);
429 static inline void tcg_out_nop(TCGContext
*s
)
431 if (use_armv7_instructions
) {
432 /* Architected nop introduced in v6k. */
433 /* ??? This is an MSR (imm) 0,0,0 insn. Anyone know if this
434 also Just So Happened to do nothing on pre-v6k so that we
435 don't need to conditionalize it? */
436 tcg_out32(s
, 0xe320f000);
438 /* Prior to that the assembler uses mov r0, r0. */
439 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, 0, 0, 0, SHIFT_IMM_LSL(0));
443 static inline void tcg_out_mov_reg(TCGContext
*s
, int cond
, int rd
, int rm
)
445 /* Simple reg-reg move, optimising out the 'do nothing' case */
447 tcg_out_dat_reg(s
, cond
, ARITH_MOV
, rd
, 0, rm
, SHIFT_IMM_LSL(0));
451 static inline void tcg_out_dat_imm(TCGContext
*s
,
452 int cond
, int opc
, int rd
, int rn
, int im
)
454 tcg_out32(s
, (cond
<< 28) | (1 << 25) | opc
|
455 (rn
<< 16) | (rd
<< 12) | im
);
458 static void tcg_out_movi32(TCGContext
*s
, int cond
, int rd
, uint32_t arg
)
462 /* For armv7, make sure not to use movw+movt when mov/mvn would do.
463 Speed things up by only checking when movt would be required.
464 Prior to armv7, have one go at fully rotated immediates before
465 doing the decomposition thing below. */
466 if (!use_armv7_instructions
|| (arg
& 0xffff0000)) {
467 rot
= encode_imm(arg
);
469 tcg_out_dat_imm(s
, cond
, ARITH_MOV
, rd
, 0,
470 rotl(arg
, rot
) | (rot
<< 7));
473 rot
= encode_imm(~arg
);
475 tcg_out_dat_imm(s
, cond
, ARITH_MVN
, rd
, 0,
476 rotl(~arg
, rot
) | (rot
<< 7));
481 /* Use movw + movt. */
482 if (use_armv7_instructions
) {
484 tcg_out32(s
, (cond
<< 28) | 0x03000000 | (rd
<< 12)
485 | ((arg
<< 4) & 0x000f0000) | (arg
& 0xfff));
486 if (arg
& 0xffff0000) {
488 tcg_out32(s
, (cond
<< 28) | 0x03400000 | (rd
<< 12)
489 | ((arg
>> 12) & 0x000f0000) | ((arg
>> 16) & 0xfff));
494 /* TODO: This is very suboptimal, we can easily have a constant
495 pool somewhere after all the instructions. */
498 /* If we have lots of leading 1's, we can shorten the sequence by
499 beginning with mvn and then clearing higher bits with eor. */
500 if (clz32(~arg
) > clz32(arg
)) {
501 opc
= ARITH_MVN
, arg
= ~arg
;
504 int i
= ctz32(arg
) & ~1;
505 rot
= ((32 - i
) << 7) & 0xf00;
506 tcg_out_dat_imm(s
, cond
, opc
, rd
, rn
, ((arg
>> i
) & 0xff) | rot
);
514 static inline void tcg_out_dat_rI(TCGContext
*s
, int cond
, int opc
, TCGArg dst
,
515 TCGArg lhs
, TCGArg rhs
, int rhs_is_const
)
517 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
518 * rhs must satisfy the "rI" constraint.
521 int rot
= encode_imm(rhs
);
523 tcg_out_dat_imm(s
, cond
, opc
, dst
, lhs
, rotl(rhs
, rot
) | (rot
<< 7));
525 tcg_out_dat_reg(s
, cond
, opc
, dst
, lhs
, rhs
, SHIFT_IMM_LSL(0));
529 static void tcg_out_dat_rIK(TCGContext
*s
, int cond
, int opc
, int opinv
,
530 TCGReg dst
, TCGReg lhs
, TCGArg rhs
,
533 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
534 * rhs must satisfy the "rIK" constraint.
537 int rot
= encode_imm(rhs
);
540 rot
= encode_imm(rhs
);
544 tcg_out_dat_imm(s
, cond
, opc
, dst
, lhs
, rotl(rhs
, rot
) | (rot
<< 7));
546 tcg_out_dat_reg(s
, cond
, opc
, dst
, lhs
, rhs
, SHIFT_IMM_LSL(0));
550 static void tcg_out_dat_rIN(TCGContext
*s
, int cond
, int opc
, int opneg
,
551 TCGArg dst
, TCGArg lhs
, TCGArg rhs
,
554 /* Emit either the reg,imm or reg,reg form of a data-processing insn.
555 * rhs must satisfy the "rIN" constraint.
558 int rot
= encode_imm(rhs
);
561 rot
= encode_imm(rhs
);
565 tcg_out_dat_imm(s
, cond
, opc
, dst
, lhs
, rotl(rhs
, rot
) | (rot
<< 7));
567 tcg_out_dat_reg(s
, cond
, opc
, dst
, lhs
, rhs
, SHIFT_IMM_LSL(0));
571 static inline void tcg_out_mul32(TCGContext
*s
, int cond
, TCGReg rd
,
572 TCGReg rn
, TCGReg rm
)
574 /* if ArchVersion() < 6 && d == n then UNPREDICTABLE; */
575 if (!use_armv6_instructions
&& rd
== rn
) {
577 /* rd == rn == rm; copy an input to tmp first. */
578 tcg_out_mov_reg(s
, cond
, TCG_REG_TMP
, rn
);
579 rm
= rn
= TCG_REG_TMP
;
586 tcg_out32(s
, (cond
<< 28) | 0x90 | (rd
<< 16) | (rm
<< 8) | rn
);
589 static inline void tcg_out_umull32(TCGContext
*s
, int cond
, TCGReg rd0
,
590 TCGReg rd1
, TCGReg rn
, TCGReg rm
)
592 /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
593 if (!use_armv6_instructions
&& (rd0
== rn
|| rd1
== rn
)) {
594 if (rd0
== rm
|| rd1
== rm
) {
595 tcg_out_mov_reg(s
, cond
, TCG_REG_TMP
, rn
);
604 tcg_out32(s
, (cond
<< 28) | 0x00800090 |
605 (rd1
<< 16) | (rd0
<< 12) | (rm
<< 8) | rn
);
608 static inline void tcg_out_smull32(TCGContext
*s
, int cond
, TCGReg rd0
,
609 TCGReg rd1
, TCGReg rn
, TCGReg rm
)
611 /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
612 if (!use_armv6_instructions
&& (rd0
== rn
|| rd1
== rn
)) {
613 if (rd0
== rm
|| rd1
== rm
) {
614 tcg_out_mov_reg(s
, cond
, TCG_REG_TMP
, rn
);
623 tcg_out32(s
, (cond
<< 28) | 0x00c00090 |
624 (rd1
<< 16) | (rd0
<< 12) | (rm
<< 8) | rn
);
627 static inline void tcg_out_sdiv(TCGContext
*s
, int cond
, int rd
, int rn
, int rm
)
629 tcg_out32(s
, 0x0710f010 | (cond
<< 28) | (rd
<< 16) | rn
| (rm
<< 8));
632 static inline void tcg_out_udiv(TCGContext
*s
, int cond
, int rd
, int rn
, int rm
)
634 tcg_out32(s
, 0x0730f010 | (cond
<< 28) | (rd
<< 16) | rn
| (rm
<< 8));
637 static inline void tcg_out_ext8s(TCGContext
*s
, int cond
,
640 if (use_armv6_instructions
) {
642 tcg_out32(s
, 0x06af0070 | (cond
<< 28) | (rd
<< 12) | rn
);
644 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
645 rd
, 0, rn
, SHIFT_IMM_LSL(24));
646 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
647 rd
, 0, rd
, SHIFT_IMM_ASR(24));
651 static inline void tcg_out_ext8u(TCGContext
*s
, int cond
,
654 tcg_out_dat_imm(s
, cond
, ARITH_AND
, rd
, rn
, 0xff);
657 static inline void tcg_out_ext16s(TCGContext
*s
, int cond
,
660 if (use_armv6_instructions
) {
662 tcg_out32(s
, 0x06bf0070 | (cond
<< 28) | (rd
<< 12) | rn
);
664 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
665 rd
, 0, rn
, SHIFT_IMM_LSL(16));
666 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
667 rd
, 0, rd
, SHIFT_IMM_ASR(16));
671 static inline void tcg_out_ext16u(TCGContext
*s
, int cond
,
674 if (use_armv6_instructions
) {
676 tcg_out32(s
, 0x06ff0070 | (cond
<< 28) | (rd
<< 12) | rn
);
678 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
679 rd
, 0, rn
, SHIFT_IMM_LSL(16));
680 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
681 rd
, 0, rd
, SHIFT_IMM_LSR(16));
685 static inline void tcg_out_bswap16s(TCGContext
*s
, int cond
, int rd
, int rn
)
687 if (use_armv6_instructions
) {
689 tcg_out32(s
, 0x06ff0fb0 | (cond
<< 28) | (rd
<< 12) | rn
);
691 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
692 TCG_REG_TMP
, 0, rn
, SHIFT_IMM_LSL(24));
693 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
694 TCG_REG_TMP
, 0, TCG_REG_TMP
, SHIFT_IMM_ASR(16));
695 tcg_out_dat_reg(s
, cond
, ARITH_ORR
,
696 rd
, TCG_REG_TMP
, rn
, SHIFT_IMM_LSR(8));
700 static inline void tcg_out_bswap16(TCGContext
*s
, int cond
, int rd
, int rn
)
702 if (use_armv6_instructions
) {
704 tcg_out32(s
, 0x06bf0fb0 | (cond
<< 28) | (rd
<< 12) | rn
);
706 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
707 TCG_REG_TMP
, 0, rn
, SHIFT_IMM_LSL(24));
708 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
709 TCG_REG_TMP
, 0, TCG_REG_TMP
, SHIFT_IMM_LSR(16));
710 tcg_out_dat_reg(s
, cond
, ARITH_ORR
,
711 rd
, TCG_REG_TMP
, rn
, SHIFT_IMM_LSR(8));
715 /* swap the two low bytes assuming that the two high input bytes and the
716 two high output bit can hold any value. */
717 static inline void tcg_out_bswap16st(TCGContext
*s
, int cond
, int rd
, int rn
)
719 if (use_armv6_instructions
) {
721 tcg_out32(s
, 0x06bf0fb0 | (cond
<< 28) | (rd
<< 12) | rn
);
723 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
724 TCG_REG_TMP
, 0, rn
, SHIFT_IMM_LSR(8));
725 tcg_out_dat_imm(s
, cond
, ARITH_AND
, TCG_REG_TMP
, TCG_REG_TMP
, 0xff);
726 tcg_out_dat_reg(s
, cond
, ARITH_ORR
,
727 rd
, TCG_REG_TMP
, rn
, SHIFT_IMM_LSL(8));
731 static inline void tcg_out_bswap32(TCGContext
*s
, int cond
, int rd
, int rn
)
733 if (use_armv6_instructions
) {
735 tcg_out32(s
, 0x06bf0f30 | (cond
<< 28) | (rd
<< 12) | rn
);
737 tcg_out_dat_reg(s
, cond
, ARITH_EOR
,
738 TCG_REG_TMP
, rn
, rn
, SHIFT_IMM_ROR(16));
739 tcg_out_dat_imm(s
, cond
, ARITH_BIC
,
740 TCG_REG_TMP
, TCG_REG_TMP
, 0xff | 0x800);
741 tcg_out_dat_reg(s
, cond
, ARITH_MOV
,
742 rd
, 0, rn
, SHIFT_IMM_ROR(8));
743 tcg_out_dat_reg(s
, cond
, ARITH_EOR
,
744 rd
, rd
, TCG_REG_TMP
, SHIFT_IMM_LSR(8));
748 bool tcg_target_deposit_valid(int ofs
, int len
)
750 /* ??? Without bfi, we could improve over generic code by combining
751 the right-shift from a non-zero ofs with the orr. We do run into
752 problems when rd == rs, and the mask generated from ofs+len doesn't
753 fit into an immediate. We would have to be careful not to pessimize
754 wrt the optimizations performed on the expanded code. */
755 return use_armv7_instructions
;
758 static inline void tcg_out_deposit(TCGContext
*s
, int cond
, TCGReg rd
,
759 TCGArg a1
, int ofs
, int len
, bool const_a1
)
762 /* bfi becomes bfc with rn == 15. */
766 tcg_out32(s
, 0x07c00010 | (cond
<< 28) | (rd
<< 12) | a1
767 | (ofs
<< 7) | ((ofs
+ len
- 1) << 16));
770 /* Note that this routine is used for both LDR and LDRH formats, so we do
771 not wish to include an immediate shift at this point. */
772 static void tcg_out_memop_r(TCGContext
*s
, int cond
, ARMInsn opc
, TCGReg rt
,
773 TCGReg rn
, TCGReg rm
, bool u
, bool p
, bool w
)
775 tcg_out32(s
, (cond
<< 28) | opc
| (u
<< 23) | (p
<< 24)
776 | (w
<< 21) | (rn
<< 16) | (rt
<< 12) | rm
);
779 static void tcg_out_memop_8(TCGContext
*s
, int cond
, ARMInsn opc
, TCGReg rt
,
780 TCGReg rn
, int imm8
, bool p
, bool w
)
787 tcg_out32(s
, (cond
<< 28) | opc
| (u
<< 23) | (p
<< 24) | (w
<< 21) |
788 (rn
<< 16) | (rt
<< 12) | ((imm8
& 0xf0) << 4) | (imm8
& 0xf));
791 static void tcg_out_memop_12(TCGContext
*s
, int cond
, ARMInsn opc
, TCGReg rt
,
792 TCGReg rn
, int imm12
, bool p
, bool w
)
799 tcg_out32(s
, (cond
<< 28) | opc
| (u
<< 23) | (p
<< 24) | (w
<< 21) |
800 (rn
<< 16) | (rt
<< 12) | imm12
);
803 static inline void tcg_out_ld32_12(TCGContext
*s
, int cond
, TCGReg rt
,
804 TCGReg rn
, int imm12
)
806 tcg_out_memop_12(s
, cond
, INSN_LDR_IMM
, rt
, rn
, imm12
, 1, 0);
809 static inline void tcg_out_st32_12(TCGContext
*s
, int cond
, TCGReg rt
,
810 TCGReg rn
, int imm12
)
812 tcg_out_memop_12(s
, cond
, INSN_STR_IMM
, rt
, rn
, imm12
, 1, 0);
815 static inline void tcg_out_ld32_r(TCGContext
*s
, int cond
, TCGReg rt
,
816 TCGReg rn
, TCGReg rm
)
818 tcg_out_memop_r(s
, cond
, INSN_LDR_REG
, rt
, rn
, rm
, 1, 1, 0);
821 static inline void tcg_out_st32_r(TCGContext
*s
, int cond
, TCGReg rt
,
822 TCGReg rn
, TCGReg rm
)
824 tcg_out_memop_r(s
, cond
, INSN_STR_REG
, rt
, rn
, rm
, 1, 1, 0);
827 /* Register pre-increment with base writeback. */
828 static inline void tcg_out_ld32_rwb(TCGContext
*s
, int cond
, TCGReg rt
,
829 TCGReg rn
, TCGReg rm
)
831 tcg_out_memop_r(s
, cond
, INSN_LDR_REG
, rt
, rn
, rm
, 1, 1, 1);
834 static inline void tcg_out_st32_rwb(TCGContext
*s
, int cond
, TCGReg rt
,
835 TCGReg rn
, TCGReg rm
)
837 tcg_out_memop_r(s
, cond
, INSN_STR_REG
, rt
, rn
, rm
, 1, 1, 1);
840 static inline void tcg_out_ld16u_8(TCGContext
*s
, int cond
, TCGReg rt
,
843 tcg_out_memop_8(s
, cond
, INSN_LDRH_IMM
, rt
, rn
, imm8
, 1, 0);
846 static inline void tcg_out_st16_8(TCGContext
*s
, int cond
, TCGReg rt
,
849 tcg_out_memop_8(s
, cond
, INSN_STRH_IMM
, rt
, rn
, imm8
, 1, 0);
852 static inline void tcg_out_ld16u_r(TCGContext
*s
, int cond
, TCGReg rt
,
853 TCGReg rn
, TCGReg rm
)
855 tcg_out_memop_r(s
, cond
, INSN_LDRH_REG
, rt
, rn
, rm
, 1, 1, 0);
858 static inline void tcg_out_st16_r(TCGContext
*s
, int cond
, TCGReg rt
,
859 TCGReg rn
, TCGReg rm
)
861 tcg_out_memop_r(s
, cond
, INSN_STRH_REG
, rt
, rn
, rm
, 1, 1, 0);
864 static inline void tcg_out_ld16s_8(TCGContext
*s
, int cond
, TCGReg rt
,
867 tcg_out_memop_8(s
, cond
, INSN_LDRSH_IMM
, rt
, rn
, imm8
, 1, 0);
870 static inline void tcg_out_ld16s_r(TCGContext
*s
, int cond
, TCGReg rt
,
871 TCGReg rn
, TCGReg rm
)
873 tcg_out_memop_r(s
, cond
, INSN_LDRSH_REG
, rt
, rn
, rm
, 1, 1, 0);
876 static inline void tcg_out_ld8_12(TCGContext
*s
, int cond
, TCGReg rt
,
877 TCGReg rn
, int imm12
)
879 tcg_out_memop_12(s
, cond
, INSN_LDRB_IMM
, rt
, rn
, imm12
, 1, 0);
882 static inline void tcg_out_st8_12(TCGContext
*s
, int cond
, TCGReg rt
,
883 TCGReg rn
, int imm12
)
885 tcg_out_memop_12(s
, cond
, INSN_STRB_IMM
, rt
, rn
, imm12
, 1, 0);
888 static inline void tcg_out_ld8_r(TCGContext
*s
, int cond
, TCGReg rt
,
889 TCGReg rn
, TCGReg rm
)
891 tcg_out_memop_r(s
, cond
, INSN_LDRB_REG
, rt
, rn
, rm
, 1, 1, 0);
894 static inline void tcg_out_st8_r(TCGContext
*s
, int cond
, TCGReg rt
,
895 TCGReg rn
, TCGReg rm
)
897 tcg_out_memop_r(s
, cond
, INSN_STRB_REG
, rt
, rn
, rm
, 1, 1, 0);
900 static inline void tcg_out_ld8s_8(TCGContext
*s
, int cond
, TCGReg rt
,
903 tcg_out_memop_8(s
, cond
, INSN_LDRSB_IMM
, rt
, rn
, imm8
, 1, 0);
906 static inline void tcg_out_ld8s_r(TCGContext
*s
, int cond
, TCGReg rt
,
907 TCGReg rn
, TCGReg rm
)
909 tcg_out_memop_r(s
, cond
, INSN_LDRSB_REG
, rt
, rn
, rm
, 1, 1, 0);
912 static inline void tcg_out_ld32u(TCGContext
*s
, int cond
,
913 int rd
, int rn
, int32_t offset
)
915 if (offset
> 0xfff || offset
< -0xfff) {
916 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
917 tcg_out_ld32_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
919 tcg_out_ld32_12(s
, cond
, rd
, rn
, offset
);
922 static inline void tcg_out_st32(TCGContext
*s
, int cond
,
923 int rd
, int rn
, int32_t offset
)
925 if (offset
> 0xfff || offset
< -0xfff) {
926 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
927 tcg_out_st32_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
929 tcg_out_st32_12(s
, cond
, rd
, rn
, offset
);
932 static inline void tcg_out_ld16u(TCGContext
*s
, int cond
,
933 int rd
, int rn
, int32_t offset
)
935 if (offset
> 0xff || offset
< -0xff) {
936 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
937 tcg_out_ld16u_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
939 tcg_out_ld16u_8(s
, cond
, rd
, rn
, offset
);
942 static inline void tcg_out_ld16s(TCGContext
*s
, int cond
,
943 int rd
, int rn
, int32_t offset
)
945 if (offset
> 0xff || offset
< -0xff) {
946 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
947 tcg_out_ld16s_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
949 tcg_out_ld16s_8(s
, cond
, rd
, rn
, offset
);
952 static inline void tcg_out_st16(TCGContext
*s
, int cond
,
953 int rd
, int rn
, int32_t offset
)
955 if (offset
> 0xff || offset
< -0xff) {
956 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
957 tcg_out_st16_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
959 tcg_out_st16_8(s
, cond
, rd
, rn
, offset
);
962 static inline void tcg_out_ld8u(TCGContext
*s
, int cond
,
963 int rd
, int rn
, int32_t offset
)
965 if (offset
> 0xfff || offset
< -0xfff) {
966 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
967 tcg_out_ld8_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
969 tcg_out_ld8_12(s
, cond
, rd
, rn
, offset
);
972 static inline void tcg_out_ld8s(TCGContext
*s
, int cond
,
973 int rd
, int rn
, int32_t offset
)
975 if (offset
> 0xff || offset
< -0xff) {
976 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
977 tcg_out_ld8s_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
979 tcg_out_ld8s_8(s
, cond
, rd
, rn
, offset
);
982 static inline void tcg_out_st8(TCGContext
*s
, int cond
,
983 int rd
, int rn
, int32_t offset
)
985 if (offset
> 0xfff || offset
< -0xfff) {
986 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, offset
);
987 tcg_out_st8_r(s
, cond
, rd
, rn
, TCG_REG_TMP
);
989 tcg_out_st8_12(s
, cond
, rd
, rn
, offset
);
992 /* The _goto case is normally between TBs within the same code buffer,
993 * and with the code buffer limited to 16MB we shouldn't need the long
996 * .... except to the prologue that is in its own buffer.
998 static inline void tcg_out_goto(TCGContext
*s
, int cond
, uint32_t addr
)
1003 /* goto to a Thumb destination isn't supported */
1007 val
= addr
- (tcg_target_long
) s
->code_ptr
;
1008 if (val
- 8 < 0x01fffffd && val
- 8 > -0x01fffffd)
1009 tcg_out_b(s
, cond
, val
);
1011 if (cond
== COND_AL
) {
1012 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_PC
, -4);
1015 tcg_out_movi32(s
, cond
, TCG_REG_TMP
, val
- 8);
1016 tcg_out_dat_reg(s
, cond
, ARITH_ADD
,
1017 TCG_REG_PC
, TCG_REG_PC
,
1018 TCG_REG_TMP
, SHIFT_IMM_LSL(0));
1023 /* The call case is mostly used for helpers - so it's not unreasonable
1024 * for them to be beyond branch range */
1025 static inline void tcg_out_call(TCGContext
*s
, uint32_t addr
)
1029 val
= addr
- (tcg_target_long
) s
->code_ptr
;
1030 if (val
- 8 < 0x02000000 && val
- 8 >= -0x02000000) {
1032 /* Use BLX if the target is in Thumb mode */
1033 if (!use_armv5_instructions
) {
1036 tcg_out_blx_imm(s
, val
);
1038 tcg_out_bl(s
, COND_AL
, val
);
1040 } else if (use_armv7_instructions
) {
1041 tcg_out_movi32(s
, COND_AL
, TCG_REG_TMP
, addr
);
1042 tcg_out_blx(s
, COND_AL
, TCG_REG_TMP
);
1044 tcg_out_dat_imm(s
, COND_AL
, ARITH_ADD
, TCG_REG_R14
, TCG_REG_PC
, 4);
1045 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_PC
, -4);
1050 static inline void tcg_out_callr(TCGContext
*s
, int cond
, int arg
)
1052 if (use_armv5_instructions
) {
1053 tcg_out_blx(s
, cond
, arg
);
1055 tcg_out_dat_reg(s
, cond
, ARITH_MOV
, TCG_REG_R14
, 0,
1056 TCG_REG_PC
, SHIFT_IMM_LSL(0));
1057 tcg_out_bx(s
, cond
, arg
);
1061 static inline void tcg_out_goto_label(TCGContext
*s
, int cond
, int label_index
)
1063 TCGLabel
*l
= &s
->labels
[label_index
];
1066 tcg_out_goto(s
, cond
, l
->u
.value
);
1068 tcg_out_reloc(s
, s
->code_ptr
, R_ARM_PC24
, label_index
, 31337);
1069 tcg_out_b_noaddr(s
, cond
);
1073 #ifdef CONFIG_SOFTMMU
1075 #include "exec/softmmu_defs.h"
1077 /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
1079 static const void * const qemu_ld_helpers
[4] = {
1086 /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr,
1087 uintxx_t val, int mmu_idx) */
1088 static const void * const qemu_st_helpers
[4] = {
1095 /* Helper routines for marshalling helper function arguments into
1096 * the correct registers and stack.
1097 * argreg is where we want to put this argument, arg is the argument itself.
1098 * Return value is the updated argreg ready for the next call.
1099 * Note that argreg 0..3 is real registers, 4+ on stack.
1101 * We provide routines for arguments which are: immediate, 32 bit
1102 * value in register, 16 and 8 bit values in register (which must be zero
1103 * extended before use) and 64 bit value in a lo:hi register pair.
1105 #define DEFINE_TCG_OUT_ARG(NAME, ARGTYPE, MOV_ARG, EXT_ARG) \
1106 static TCGReg NAME(TCGContext *s, TCGReg argreg, ARGTYPE arg) \
1109 MOV_ARG(s, COND_AL, argreg, arg); \
1111 int ofs = (argreg - 4) * 4; \
1113 assert(ofs + 4 <= TCG_STATIC_CALL_ARGS_SIZE); \
1114 tcg_out_st32_12(s, COND_AL, arg, TCG_REG_CALL_STACK, ofs); \
1116 return argreg + 1; \
1119 DEFINE_TCG_OUT_ARG(tcg_out_arg_imm32
, uint32_t, tcg_out_movi32
,
1120 (tcg_out_movi32(s
, COND_AL
, TCG_REG_TMP
, arg
), arg
= TCG_REG_TMP
))
1121 DEFINE_TCG_OUT_ARG(tcg_out_arg_reg8
, TCGReg
, tcg_out_ext8u
,
1122 (tcg_out_ext8u(s
, COND_AL
, TCG_REG_TMP
, arg
), arg
= TCG_REG_TMP
))
1123 DEFINE_TCG_OUT_ARG(tcg_out_arg_reg16
, TCGReg
, tcg_out_ext16u
,
1124 (tcg_out_ext16u(s
, COND_AL
, TCG_REG_TMP
, arg
), arg
= TCG_REG_TMP
))
1125 DEFINE_TCG_OUT_ARG(tcg_out_arg_reg32
, TCGReg
, tcg_out_mov_reg
, )
1127 static TCGReg
tcg_out_arg_reg64(TCGContext
*s
, TCGReg argreg
,
1128 TCGReg arglo
, TCGReg arghi
)
1130 /* 64 bit arguments must go in even/odd register pairs
1131 * and in 8-aligned stack slots.
1136 argreg
= tcg_out_arg_reg32(s
, argreg
, arglo
);
1137 argreg
= tcg_out_arg_reg32(s
, argreg
, arghi
);
1141 #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
1143 /* Load and compare a TLB entry, leaving the flags set. Leaves R2 pointing
1144 to the tlb entry. Clobbers R1 and TMP. */
1146 static void tcg_out_tlb_read(TCGContext
*s
, TCGReg addrlo
, TCGReg addrhi
,
1147 int s_bits
, int tlb_offset
)
1149 TCGReg base
= TCG_AREG0
;
1151 /* Should generate something like the following:
1153 * shr tmp, addr_reg, #TARGET_PAGE_BITS (1)
1154 * add r2, env, #off & 0xff00
1155 * and r0, tmp, #(CPU_TLB_SIZE - 1) (2)
1156 * add r2, r2, r0, lsl #CPU_TLB_ENTRY_BITS (3)
1157 * ldr r0, [r2, #off & 0xff]! (4)
1158 * tst addr_reg, #s_mask
1159 * cmpeq r0, tmp, lsl #TARGET_PAGE_BITS (5)
1161 * v7 (not implemented yet):
1162 * ubfx r2, addr_reg, #TARGET_PAGE_BITS, #CPU_TLB_BITS (1)
1163 * movw tmp, #~TARGET_PAGE_MASK & ~s_mask
1165 * add r2, env, r2, lsl #CPU_TLB_ENTRY_BITS (2)
1166 * bic tmp, addr_reg, tmp
1167 * ldr r0, [r2, r0]! (3)
1170 # if CPU_TLB_BITS > 8
1173 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, TCG_REG_TMP
,
1174 0, addrlo
, SHIFT_IMM_LSR(TARGET_PAGE_BITS
));
1176 /* We assume that the offset is contained within 16 bits. */
1177 assert((tlb_offset
& ~0xffff) == 0);
1178 if (tlb_offset
> 0xff) {
1179 tcg_out_dat_imm(s
, COND_AL
, ARITH_ADD
, TCG_REG_R2
, base
,
1180 (24 << 7) | (tlb_offset
>> 8));
1185 tcg_out_dat_imm(s
, COND_AL
, ARITH_AND
,
1186 TCG_REG_R0
, TCG_REG_TMP
, CPU_TLB_SIZE
- 1);
1187 tcg_out_dat_reg(s
, COND_AL
, ARITH_ADD
, TCG_REG_R2
, base
,
1188 TCG_REG_R0
, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS
));
1190 /* Load the tlb comparator. Use ldrd if needed and available,
1191 but due to how the pointer needs setting up, ldm isn't useful.
1192 Base arm5 doesn't have ldrd, but armv5te does. */
1193 if (use_armv6_instructions
&& TARGET_LONG_BITS
== 64) {
1194 tcg_out_memop_8(s
, COND_AL
, INSN_LDRD_IMM
, TCG_REG_R0
,
1195 TCG_REG_R2
, tlb_offset
, 1, 1);
1197 tcg_out_memop_12(s
, COND_AL
, INSN_LDR_IMM
, TCG_REG_R0
,
1198 TCG_REG_R2
, tlb_offset
, 1, 1);
1199 if (TARGET_LONG_BITS
== 64) {
1200 tcg_out_memop_12(s
, COND_AL
, INSN_LDR_IMM
, TCG_REG_R1
,
1201 TCG_REG_R2
, 4, 1, 0);
1205 /* Check alignment. */
1207 tcg_out_dat_imm(s
, COND_AL
, ARITH_TST
,
1208 0, addrlo
, (1 << s_bits
) - 1);
1211 tcg_out_dat_reg(s
, (s_bits
? COND_EQ
: COND_AL
), ARITH_CMP
, 0,
1212 TCG_REG_R0
, TCG_REG_TMP
, SHIFT_IMM_LSL(TARGET_PAGE_BITS
));
1214 if (TARGET_LONG_BITS
== 64) {
1215 tcg_out_dat_reg(s
, COND_EQ
, ARITH_CMP
, 0,
1216 TCG_REG_R1
, addrhi
, SHIFT_IMM_LSL(0));
1220 /* Record the context of a call to the out of line helper code for the slow
1221 path for a load or store, so that we can later generate the correct
1223 static void add_qemu_ldst_label(TCGContext
*s
, int is_ld
, int opc
,
1224 int data_reg
, int data_reg2
, int addrlo_reg
,
1225 int addrhi_reg
, int mem_index
,
1226 uint8_t *raddr
, uint8_t *label_ptr
)
1229 TCGLabelQemuLdst
*label
;
1231 if (s
->nb_qemu_ldst_labels
>= TCG_MAX_QEMU_LDST
) {
1235 idx
= s
->nb_qemu_ldst_labels
++;
1236 label
= (TCGLabelQemuLdst
*)&s
->qemu_ldst_labels
[idx
];
1237 label
->is_ld
= is_ld
;
1239 label
->datalo_reg
= data_reg
;
1240 label
->datahi_reg
= data_reg2
;
1241 label
->addrlo_reg
= addrlo_reg
;
1242 label
->addrhi_reg
= addrhi_reg
;
1243 label
->mem_index
= mem_index
;
1244 label
->raddr
= raddr
;
1245 label
->label_ptr
[0] = label_ptr
;
1248 static void tcg_out_qemu_ld_slow_path(TCGContext
*s
, TCGLabelQemuLdst
*lb
)
1250 TCGReg argreg
, data_reg
, data_reg2
;
1253 reloc_pc24(lb
->label_ptr
[0], (tcg_target_long
)s
->code_ptr
);
1255 argreg
= tcg_out_arg_reg32(s
, TCG_REG_R0
, TCG_AREG0
);
1256 if (TARGET_LONG_BITS
== 64) {
1257 argreg
= tcg_out_arg_reg64(s
, argreg
, lb
->addrlo_reg
, lb
->addrhi_reg
);
1259 argreg
= tcg_out_arg_reg32(s
, argreg
, lb
->addrlo_reg
);
1261 argreg
= tcg_out_arg_imm32(s
, argreg
, lb
->mem_index
);
1262 tcg_out_call(s
, (tcg_target_long
) qemu_ld_helpers
[lb
->opc
& 3]);
1264 data_reg
= lb
->datalo_reg
;
1265 data_reg2
= lb
->datahi_reg
;
1267 start
= s
->code_ptr
;
1270 tcg_out_ext8s(s
, COND_AL
, data_reg
, TCG_REG_R0
);
1273 tcg_out_ext16s(s
, COND_AL
, data_reg
, TCG_REG_R0
);
1279 tcg_out_mov_reg(s
, COND_AL
, data_reg
, TCG_REG_R0
);
1282 tcg_out_mov_reg(s
, COND_AL
, data_reg
, TCG_REG_R0
);
1283 tcg_out_mov_reg(s
, COND_AL
, data_reg2
, TCG_REG_R1
);
1287 /* For GETPC_LDST in exec-all.h, we architect exactly 2 insns between
1288 the call and the branch back to straight-line code. Note that the
1289 moves above could be elided by register allocation, nor do we know
1290 which code alternative we chose for extension. */
1291 switch (s
->code_ptr
- start
) {
1304 tcg_out_goto(s
, COND_AL
, (tcg_target_long
)lb
->raddr
);
1307 static void tcg_out_qemu_st_slow_path(TCGContext
*s
, TCGLabelQemuLdst
*lb
)
1309 TCGReg argreg
, data_reg
, data_reg2
;
1311 reloc_pc24(lb
->label_ptr
[0], (tcg_target_long
)s
->code_ptr
);
1313 argreg
= TCG_REG_R0
;
1314 argreg
= tcg_out_arg_reg32(s
, argreg
, TCG_AREG0
);
1315 if (TARGET_LONG_BITS
== 64) {
1316 argreg
= tcg_out_arg_reg64(s
, argreg
, lb
->addrlo_reg
, lb
->addrhi_reg
);
1318 argreg
= tcg_out_arg_reg32(s
, argreg
, lb
->addrlo_reg
);
1321 data_reg
= lb
->datalo_reg
;
1322 data_reg2
= lb
->datahi_reg
;
1325 argreg
= tcg_out_arg_reg8(s
, argreg
, data_reg
);
1328 argreg
= tcg_out_arg_reg16(s
, argreg
, data_reg
);
1331 argreg
= tcg_out_arg_reg32(s
, argreg
, data_reg
);
1334 argreg
= tcg_out_arg_reg64(s
, argreg
, data_reg
, data_reg2
);
1338 argreg
= tcg_out_arg_imm32(s
, argreg
, lb
->mem_index
);
1339 tcg_out_call(s
, (tcg_target_long
) qemu_st_helpers
[lb
->opc
& 3]);
1341 /* For GETPC_LDST in exec-all.h, we architect exactly 2 insns between
1342 the call and the branch back to straight-line code. */
1345 tcg_out_goto(s
, COND_AL
, (tcg_target_long
)lb
->raddr
);
1347 #endif /* SOFTMMU */
1349 static void tcg_out_qemu_ld(TCGContext
*s
, const TCGArg
*args
, int opc
)
1351 TCGReg addr_reg
, data_reg
, data_reg2
;
1353 #ifdef CONFIG_SOFTMMU
1354 int mem_index
, s_bits
;
1358 #ifdef TARGET_WORDS_BIGENDIAN
1365 data_reg2
= (opc
== 3 ? *args
++ : 0);
1367 #ifdef CONFIG_SOFTMMU
1368 addr_reg2
= (TARGET_LONG_BITS
== 64 ? *args
++ : 0);
1372 tcg_out_tlb_read(s
, addr_reg
, addr_reg2
, s_bits
,
1373 offsetof(CPUArchState
, tlb_table
[mem_index
][0].addr_read
));
1375 label_ptr
= s
->code_ptr
;
1376 tcg_out_b_noaddr(s
, COND_NE
);
1378 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_R1
, TCG_REG_R2
,
1379 offsetof(CPUTLBEntry
, addend
)
1380 - offsetof(CPUTLBEntry
, addr_read
));
1384 tcg_out_ld8_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1387 tcg_out_ld8s_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1390 tcg_out_ld16u_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1392 tcg_out_bswap16(s
, COND_AL
, data_reg
, data_reg
);
1397 tcg_out_ld16u_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1398 tcg_out_bswap16s(s
, COND_AL
, data_reg
, data_reg
);
1400 tcg_out_ld16s_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1405 tcg_out_ld32_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1407 tcg_out_bswap32(s
, COND_AL
, data_reg
, data_reg
);
1412 tcg_out_ld32_rwb(s
, COND_AL
, data_reg2
, TCG_REG_R1
, addr_reg
);
1413 tcg_out_ld32_12(s
, COND_AL
, data_reg
, TCG_REG_R1
, 4);
1414 tcg_out_bswap32(s
, COND_AL
, data_reg2
, data_reg2
);
1415 tcg_out_bswap32(s
, COND_AL
, data_reg
, data_reg
);
1417 tcg_out_ld32_rwb(s
, COND_AL
, data_reg
, TCG_REG_R1
, addr_reg
);
1418 tcg_out_ld32_12(s
, COND_AL
, data_reg2
, TCG_REG_R1
, 4);
1423 add_qemu_ldst_label(s
, 1, opc
, data_reg
, data_reg2
, addr_reg
, addr_reg2
,
1424 mem_index
, s
->code_ptr
, label_ptr
);
1425 #else /* !CONFIG_SOFTMMU */
1427 uint32_t offset
= GUEST_BASE
;
1431 i
= ctz32(offset
) & ~1;
1432 rot
= ((32 - i
) << 7) & 0xf00;
1434 tcg_out_dat_imm(s
, COND_AL
, ARITH_ADD
, TCG_REG_TMP
, addr_reg
,
1435 ((offset
>> i
) & 0xff) | rot
);
1436 addr_reg
= TCG_REG_TMP
;
1437 offset
&= ~(0xff << i
);
1442 tcg_out_ld8_12(s
, COND_AL
, data_reg
, addr_reg
, 0);
1445 tcg_out_ld8s_8(s
, COND_AL
, data_reg
, addr_reg
, 0);
1448 tcg_out_ld16u_8(s
, COND_AL
, data_reg
, addr_reg
, 0);
1450 tcg_out_bswap16(s
, COND_AL
, data_reg
, data_reg
);
1455 tcg_out_ld16u_8(s
, COND_AL
, data_reg
, addr_reg
, 0);
1456 tcg_out_bswap16s(s
, COND_AL
, data_reg
, data_reg
);
1458 tcg_out_ld16s_8(s
, COND_AL
, data_reg
, addr_reg
, 0);
1463 tcg_out_ld32_12(s
, COND_AL
, data_reg
, addr_reg
, 0);
1465 tcg_out_bswap32(s
, COND_AL
, data_reg
, data_reg
);
1469 /* TODO: use block load -
1470 * check that data_reg2 > data_reg or the other way */
1471 if (data_reg
== addr_reg
) {
1472 tcg_out_ld32_12(s
, COND_AL
, data_reg2
, addr_reg
, bswap
? 0 : 4);
1473 tcg_out_ld32_12(s
, COND_AL
, data_reg
, addr_reg
, bswap
? 4 : 0);
1475 tcg_out_ld32_12(s
, COND_AL
, data_reg
, addr_reg
, bswap
? 4 : 0);
1476 tcg_out_ld32_12(s
, COND_AL
, data_reg2
, addr_reg
, bswap
? 0 : 4);
1479 tcg_out_bswap32(s
, COND_AL
, data_reg
, data_reg
);
1480 tcg_out_bswap32(s
, COND_AL
, data_reg2
, data_reg2
);
1487 static void tcg_out_qemu_st(TCGContext
*s
, const TCGArg
*args
, int opc
)
1489 TCGReg addr_reg
, data_reg
, data_reg2
;
1491 #ifdef CONFIG_SOFTMMU
1492 int mem_index
, s_bits
;
1496 #ifdef TARGET_WORDS_BIGENDIAN
1503 data_reg2
= (opc
== 3 ? *args
++ : 0);
1505 #ifdef CONFIG_SOFTMMU
1506 addr_reg2
= (TARGET_LONG_BITS
== 64 ? *args
++ : 0);
1510 tcg_out_tlb_read(s
, addr_reg
, addr_reg2
, s_bits
,
1511 offsetof(CPUArchState
,
1512 tlb_table
[mem_index
][0].addr_write
));
1514 label_ptr
= s
->code_ptr
;
1515 tcg_out_b_noaddr(s
, COND_NE
);
1517 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_R1
, TCG_REG_R2
,
1518 offsetof(CPUTLBEntry
, addend
)
1519 - offsetof(CPUTLBEntry
, addr_write
));
1523 tcg_out_st8_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1527 tcg_out_bswap16st(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1528 tcg_out_st16_r(s
, COND_AL
, TCG_REG_R0
, addr_reg
, TCG_REG_R1
);
1530 tcg_out_st16_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1536 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1537 tcg_out_st32_r(s
, COND_AL
, TCG_REG_R0
, addr_reg
, TCG_REG_R1
);
1539 tcg_out_st32_r(s
, COND_AL
, data_reg
, addr_reg
, TCG_REG_R1
);
1544 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg2
);
1545 tcg_out_st32_rwb(s
, COND_AL
, TCG_REG_R0
, TCG_REG_R1
, addr_reg
);
1546 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1547 tcg_out_st32_12(s
, COND_AL
, TCG_REG_R0
, TCG_REG_R1
, 4);
1549 tcg_out_st32_rwb(s
, COND_AL
, data_reg
, TCG_REG_R1
, addr_reg
);
1550 tcg_out_st32_12(s
, COND_AL
, data_reg2
, TCG_REG_R1
, 4);
1555 add_qemu_ldst_label(s
, 0, opc
, data_reg
, data_reg2
, addr_reg
, addr_reg2
,
1556 mem_index
, s
->code_ptr
, label_ptr
);
1557 #else /* !CONFIG_SOFTMMU */
1559 uint32_t offset
= GUEST_BASE
;
1564 i
= ctz32(offset
) & ~1;
1565 rot
= ((32 - i
) << 7) & 0xf00;
1567 tcg_out_dat_imm(s
, COND_AL
, ARITH_ADD
, TCG_REG_R1
, addr_reg
,
1568 ((offset
>> i
) & 0xff) | rot
);
1569 addr_reg
= TCG_REG_R1
;
1570 offset
&= ~(0xff << i
);
1575 tcg_out_st8_12(s
, COND_AL
, data_reg
, addr_reg
, 0);
1579 tcg_out_bswap16st(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1580 tcg_out_st16_8(s
, COND_AL
, TCG_REG_R0
, addr_reg
, 0);
1582 tcg_out_st16_8(s
, COND_AL
, data_reg
, addr_reg
, 0);
1588 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1589 tcg_out_st32_12(s
, COND_AL
, TCG_REG_R0
, addr_reg
, 0);
1591 tcg_out_st32_12(s
, COND_AL
, data_reg
, addr_reg
, 0);
1595 /* TODO: use block store -
1596 * check that data_reg2 > data_reg or the other way */
1598 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg2
);
1599 tcg_out_st32_12(s
, COND_AL
, TCG_REG_R0
, addr_reg
, 0);
1600 tcg_out_bswap32(s
, COND_AL
, TCG_REG_R0
, data_reg
);
1601 tcg_out_st32_12(s
, COND_AL
, TCG_REG_R0
, addr_reg
, 4);
1603 tcg_out_st32_12(s
, COND_AL
, data_reg
, addr_reg
, 0);
1604 tcg_out_st32_12(s
, COND_AL
, data_reg2
, addr_reg
, 4);
1611 static uint8_t *tb_ret_addr
;
1613 static inline void tcg_out_op(TCGContext
*s
, TCGOpcode opc
,
1614 const TCGArg
*args
, const int *const_args
)
1616 TCGArg a0
, a1
, a2
, a3
, a4
, a5
;
1620 case INDEX_op_exit_tb
:
1621 if (use_armv7_instructions
|| check_fit_imm(args
[0])) {
1622 tcg_out_movi32(s
, COND_AL
, TCG_REG_R0
, args
[0]);
1623 tcg_out_goto(s
, COND_AL
, (tcg_target_ulong
) tb_ret_addr
);
1625 uint8_t *ld_ptr
= s
->code_ptr
;
1626 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_R0
, TCG_REG_PC
, 0);
1627 tcg_out_goto(s
, COND_AL
, (tcg_target_ulong
) tb_ret_addr
);
1628 *ld_ptr
= (uint8_t) (s
->code_ptr
- ld_ptr
) - 8;
1629 tcg_out32(s
, args
[0]);
1632 case INDEX_op_goto_tb
:
1633 if (s
->tb_jmp_offset
) {
1634 /* Direct jump method */
1635 #if defined(USE_DIRECT_JUMP)
1636 s
->tb_jmp_offset
[args
[0]] = s
->code_ptr
- s
->code_buf
;
1637 tcg_out_b_noaddr(s
, COND_AL
);
1639 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_PC
, -4);
1640 s
->tb_jmp_offset
[args
[0]] = s
->code_ptr
- s
->code_buf
;
1644 /* Indirect jump method */
1646 c
= (int) (s
->tb_next
+ args
[0]) - ((int) s
->code_ptr
+ 8);
1647 if (c
> 0xfff || c
< -0xfff) {
1648 tcg_out_movi32(s
, COND_AL
, TCG_REG_R0
,
1649 (tcg_target_long
) (s
->tb_next
+ args
[0]));
1650 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_R0
, 0);
1652 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_PC
, c
);
1654 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_R0
, TCG_REG_PC
, 0);
1655 tcg_out_ld32_12(s
, COND_AL
, TCG_REG_PC
, TCG_REG_R0
, 0);
1656 tcg_out32(s
, (tcg_target_long
) (s
->tb_next
+ args
[0]));
1659 s
->tb_next_offset
[args
[0]] = s
->code_ptr
- s
->code_buf
;
1663 tcg_out_call(s
, args
[0]);
1665 tcg_out_callr(s
, COND_AL
, args
[0]);
1668 tcg_out_goto_label(s
, COND_AL
, args
[0]);
1671 case INDEX_op_ld8u_i32
:
1672 tcg_out_ld8u(s
, COND_AL
, args
[0], args
[1], args
[2]);
1674 case INDEX_op_ld8s_i32
:
1675 tcg_out_ld8s(s
, COND_AL
, args
[0], args
[1], args
[2]);
1677 case INDEX_op_ld16u_i32
:
1678 tcg_out_ld16u(s
, COND_AL
, args
[0], args
[1], args
[2]);
1680 case INDEX_op_ld16s_i32
:
1681 tcg_out_ld16s(s
, COND_AL
, args
[0], args
[1], args
[2]);
1683 case INDEX_op_ld_i32
:
1684 tcg_out_ld32u(s
, COND_AL
, args
[0], args
[1], args
[2]);
1686 case INDEX_op_st8_i32
:
1687 tcg_out_st8(s
, COND_AL
, args
[0], args
[1], args
[2]);
1689 case INDEX_op_st16_i32
:
1690 tcg_out_st16(s
, COND_AL
, args
[0], args
[1], args
[2]);
1692 case INDEX_op_st_i32
:
1693 tcg_out_st32(s
, COND_AL
, args
[0], args
[1], args
[2]);
1696 case INDEX_op_mov_i32
:
1697 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
,
1698 args
[0], 0, args
[1], SHIFT_IMM_LSL(0));
1700 case INDEX_op_movi_i32
:
1701 tcg_out_movi32(s
, COND_AL
, args
[0], args
[1]);
1703 case INDEX_op_movcond_i32
:
1704 /* Constraints mean that v2 is always in the same register as dest,
1705 * so we only need to do "if condition passed, move v1 to dest".
1707 tcg_out_dat_rIN(s
, COND_AL
, ARITH_CMP
, ARITH_CMN
, 0,
1708 args
[1], args
[2], const_args
[2]);
1709 tcg_out_dat_rIK(s
, tcg_cond_to_arm_cond
[args
[5]], ARITH_MOV
,
1710 ARITH_MVN
, args
[0], 0, args
[3], const_args
[3]);
1712 case INDEX_op_add_i32
:
1713 tcg_out_dat_rIN(s
, COND_AL
, ARITH_ADD
, ARITH_SUB
,
1714 args
[0], args
[1], args
[2], const_args
[2]);
1716 case INDEX_op_sub_i32
:
1717 if (const_args
[1]) {
1718 if (const_args
[2]) {
1719 tcg_out_movi32(s
, COND_AL
, args
[0], args
[1] - args
[2]);
1721 tcg_out_dat_rI(s
, COND_AL
, ARITH_RSB
,
1722 args
[0], args
[2], args
[1], 1);
1725 tcg_out_dat_rIN(s
, COND_AL
, ARITH_SUB
, ARITH_ADD
,
1726 args
[0], args
[1], args
[2], const_args
[2]);
1729 case INDEX_op_and_i32
:
1730 tcg_out_dat_rIK(s
, COND_AL
, ARITH_AND
, ARITH_BIC
,
1731 args
[0], args
[1], args
[2], const_args
[2]);
1733 case INDEX_op_andc_i32
:
1734 tcg_out_dat_rIK(s
, COND_AL
, ARITH_BIC
, ARITH_AND
,
1735 args
[0], args
[1], args
[2], const_args
[2]);
1737 case INDEX_op_or_i32
:
1740 case INDEX_op_xor_i32
:
1744 tcg_out_dat_rI(s
, COND_AL
, c
, args
[0], args
[1], args
[2], const_args
[2]);
1746 case INDEX_op_add2_i32
:
1747 a0
= args
[0], a1
= args
[1], a2
= args
[2];
1748 a3
= args
[3], a4
= args
[4], a5
= args
[5];
1749 if (a0
== a3
|| (a0
== a5
&& !const_args
[5])) {
1752 tcg_out_dat_rIN(s
, COND_AL
, ARITH_ADD
| TO_CPSR
, ARITH_SUB
| TO_CPSR
,
1753 a0
, a2
, a4
, const_args
[4]);
1754 tcg_out_dat_rIK(s
, COND_AL
, ARITH_ADC
, ARITH_SBC
,
1755 a1
, a3
, a5
, const_args
[5]);
1756 tcg_out_mov_reg(s
, COND_AL
, args
[0], a0
);
1758 case INDEX_op_sub2_i32
:
1759 a0
= args
[0], a1
= args
[1], a2
= args
[2];
1760 a3
= args
[3], a4
= args
[4], a5
= args
[5];
1761 if ((a0
== a3
&& !const_args
[3]) || (a0
== a5
&& !const_args
[5])) {
1764 if (const_args
[2]) {
1765 if (const_args
[4]) {
1766 tcg_out_movi32(s
, COND_AL
, a0
, a4
);
1769 tcg_out_dat_rI(s
, COND_AL
, ARITH_RSB
| TO_CPSR
, a0
, a4
, a2
, 1);
1771 tcg_out_dat_rIN(s
, COND_AL
, ARITH_SUB
| TO_CPSR
,
1772 ARITH_ADD
| TO_CPSR
, a0
, a2
, a4
, const_args
[4]);
1774 if (const_args
[3]) {
1775 if (const_args
[5]) {
1776 tcg_out_movi32(s
, COND_AL
, a1
, a5
);
1779 tcg_out_dat_rI(s
, COND_AL
, ARITH_RSC
, a1
, a5
, a3
, 1);
1781 tcg_out_dat_rIK(s
, COND_AL
, ARITH_SBC
, ARITH_ADC
,
1782 a1
, a3
, a5
, const_args
[5]);
1784 tcg_out_mov_reg(s
, COND_AL
, args
[0], a0
);
1786 case INDEX_op_neg_i32
:
1787 tcg_out_dat_imm(s
, COND_AL
, ARITH_RSB
, args
[0], args
[1], 0);
1789 case INDEX_op_not_i32
:
1790 tcg_out_dat_reg(s
, COND_AL
,
1791 ARITH_MVN
, args
[0], 0, args
[1], SHIFT_IMM_LSL(0));
1793 case INDEX_op_mul_i32
:
1794 tcg_out_mul32(s
, COND_AL
, args
[0], args
[1], args
[2]);
1796 case INDEX_op_mulu2_i32
:
1797 tcg_out_umull32(s
, COND_AL
, args
[0], args
[1], args
[2], args
[3]);
1799 case INDEX_op_muls2_i32
:
1800 tcg_out_smull32(s
, COND_AL
, args
[0], args
[1], args
[2], args
[3]);
1802 /* XXX: Perhaps args[2] & 0x1f is wrong */
1803 case INDEX_op_shl_i32
:
1805 SHIFT_IMM_LSL(args
[2] & 0x1f) : SHIFT_REG_LSL(args
[2]);
1807 case INDEX_op_shr_i32
:
1808 c
= const_args
[2] ? (args
[2] & 0x1f) ? SHIFT_IMM_LSR(args
[2] & 0x1f) :
1809 SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args
[2]);
1811 case INDEX_op_sar_i32
:
1812 c
= const_args
[2] ? (args
[2] & 0x1f) ? SHIFT_IMM_ASR(args
[2] & 0x1f) :
1813 SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args
[2]);
1815 case INDEX_op_rotr_i32
:
1816 c
= const_args
[2] ? (args
[2] & 0x1f) ? SHIFT_IMM_ROR(args
[2] & 0x1f) :
1817 SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args
[2]);
1820 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, args
[0], 0, args
[1], c
);
1823 case INDEX_op_rotl_i32
:
1824 if (const_args
[2]) {
1825 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, args
[0], 0, args
[1],
1826 ((0x20 - args
[2]) & 0x1f) ?
1827 SHIFT_IMM_ROR((0x20 - args
[2]) & 0x1f) :
1830 tcg_out_dat_imm(s
, COND_AL
, ARITH_RSB
, TCG_REG_TMP
, args
[1], 0x20);
1831 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, args
[0], 0, args
[1],
1832 SHIFT_REG_ROR(TCG_REG_TMP
));
1836 case INDEX_op_brcond_i32
:
1837 tcg_out_dat_rIN(s
, COND_AL
, ARITH_CMP
, ARITH_CMN
, 0,
1838 args
[0], args
[1], const_args
[1]);
1839 tcg_out_goto_label(s
, tcg_cond_to_arm_cond
[args
[2]], args
[3]);
1841 case INDEX_op_brcond2_i32
:
1842 /* The resulting conditions are:
1843 * TCG_COND_EQ --> a0 == a2 && a1 == a3,
1844 * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
1845 * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
1846 * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
1847 * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
1848 * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
1850 tcg_out_dat_rIN(s
, COND_AL
, ARITH_CMP
, ARITH_CMN
, 0,
1851 args
[1], args
[3], const_args
[3]);
1852 tcg_out_dat_rIN(s
, COND_EQ
, ARITH_CMP
, ARITH_CMN
, 0,
1853 args
[0], args
[2], const_args
[2]);
1854 tcg_out_goto_label(s
, tcg_cond_to_arm_cond
[args
[4]], args
[5]);
1856 case INDEX_op_setcond_i32
:
1857 tcg_out_dat_rIN(s
, COND_AL
, ARITH_CMP
, ARITH_CMN
, 0,
1858 args
[1], args
[2], const_args
[2]);
1859 tcg_out_dat_imm(s
, tcg_cond_to_arm_cond
[args
[3]],
1860 ARITH_MOV
, args
[0], 0, 1);
1861 tcg_out_dat_imm(s
, tcg_cond_to_arm_cond
[tcg_invert_cond(args
[3])],
1862 ARITH_MOV
, args
[0], 0, 0);
1864 case INDEX_op_setcond2_i32
:
1865 /* See brcond2_i32 comment */
1866 tcg_out_dat_rIN(s
, COND_AL
, ARITH_CMP
, ARITH_CMN
, 0,
1867 args
[2], args
[4], const_args
[4]);
1868 tcg_out_dat_rIN(s
, COND_EQ
, ARITH_CMP
, ARITH_CMN
, 0,
1869 args
[1], args
[3], const_args
[3]);
1870 tcg_out_dat_imm(s
, tcg_cond_to_arm_cond
[args
[5]],
1871 ARITH_MOV
, args
[0], 0, 1);
1872 tcg_out_dat_imm(s
, tcg_cond_to_arm_cond
[tcg_invert_cond(args
[5])],
1873 ARITH_MOV
, args
[0], 0, 0);
1876 case INDEX_op_qemu_ld8u
:
1877 tcg_out_qemu_ld(s
, args
, 0);
1879 case INDEX_op_qemu_ld8s
:
1880 tcg_out_qemu_ld(s
, args
, 0 | 4);
1882 case INDEX_op_qemu_ld16u
:
1883 tcg_out_qemu_ld(s
, args
, 1);
1885 case INDEX_op_qemu_ld16s
:
1886 tcg_out_qemu_ld(s
, args
, 1 | 4);
1888 case INDEX_op_qemu_ld32
:
1889 tcg_out_qemu_ld(s
, args
, 2);
1891 case INDEX_op_qemu_ld64
:
1892 tcg_out_qemu_ld(s
, args
, 3);
1895 case INDEX_op_qemu_st8
:
1896 tcg_out_qemu_st(s
, args
, 0);
1898 case INDEX_op_qemu_st16
:
1899 tcg_out_qemu_st(s
, args
, 1);
1901 case INDEX_op_qemu_st32
:
1902 tcg_out_qemu_st(s
, args
, 2);
1904 case INDEX_op_qemu_st64
:
1905 tcg_out_qemu_st(s
, args
, 3);
1908 case INDEX_op_bswap16_i32
:
1909 tcg_out_bswap16(s
, COND_AL
, args
[0], args
[1]);
1911 case INDEX_op_bswap32_i32
:
1912 tcg_out_bswap32(s
, COND_AL
, args
[0], args
[1]);
1915 case INDEX_op_ext8s_i32
:
1916 tcg_out_ext8s(s
, COND_AL
, args
[0], args
[1]);
1918 case INDEX_op_ext16s_i32
:
1919 tcg_out_ext16s(s
, COND_AL
, args
[0], args
[1]);
1921 case INDEX_op_ext16u_i32
:
1922 tcg_out_ext16u(s
, COND_AL
, args
[0], args
[1]);
1925 case INDEX_op_deposit_i32
:
1926 tcg_out_deposit(s
, COND_AL
, args
[0], args
[2],
1927 args
[3], args
[4], const_args
[2]);
1930 case INDEX_op_div_i32
:
1931 tcg_out_sdiv(s
, COND_AL
, args
[0], args
[1], args
[2]);
1933 case INDEX_op_divu_i32
:
1934 tcg_out_udiv(s
, COND_AL
, args
[0], args
[1], args
[2]);
1942 #ifdef CONFIG_SOFTMMU
1943 /* Generate TB finalization at the end of block. */
1944 void tcg_out_tb_finalize(TCGContext
*s
)
1947 for (i
= 0; i
< s
->nb_qemu_ldst_labels
; i
++) {
1948 TCGLabelQemuLdst
*label
= &s
->qemu_ldst_labels
[i
];
1950 tcg_out_qemu_ld_slow_path(s
, label
);
1952 tcg_out_qemu_st_slow_path(s
, label
);
1956 #endif /* SOFTMMU */
1958 static const TCGTargetOpDef arm_op_defs
[] = {
1959 { INDEX_op_exit_tb
, { } },
1960 { INDEX_op_goto_tb
, { } },
1961 { INDEX_op_call
, { "ri" } },
1962 { INDEX_op_br
, { } },
1964 { INDEX_op_mov_i32
, { "r", "r" } },
1965 { INDEX_op_movi_i32
, { "r" } },
1967 { INDEX_op_ld8u_i32
, { "r", "r" } },
1968 { INDEX_op_ld8s_i32
, { "r", "r" } },
1969 { INDEX_op_ld16u_i32
, { "r", "r" } },
1970 { INDEX_op_ld16s_i32
, { "r", "r" } },
1971 { INDEX_op_ld_i32
, { "r", "r" } },
1972 { INDEX_op_st8_i32
, { "r", "r" } },
1973 { INDEX_op_st16_i32
, { "r", "r" } },
1974 { INDEX_op_st_i32
, { "r", "r" } },
1976 /* TODO: "r", "r", "ri" */
1977 { INDEX_op_add_i32
, { "r", "r", "rIN" } },
1978 { INDEX_op_sub_i32
, { "r", "rI", "rIN" } },
1979 { INDEX_op_mul_i32
, { "r", "r", "r" } },
1980 { INDEX_op_mulu2_i32
, { "r", "r", "r", "r" } },
1981 { INDEX_op_muls2_i32
, { "r", "r", "r", "r" } },
1982 { INDEX_op_and_i32
, { "r", "r", "rIK" } },
1983 { INDEX_op_andc_i32
, { "r", "r", "rIK" } },
1984 { INDEX_op_or_i32
, { "r", "r", "rI" } },
1985 { INDEX_op_xor_i32
, { "r", "r", "rI" } },
1986 { INDEX_op_neg_i32
, { "r", "r" } },
1987 { INDEX_op_not_i32
, { "r", "r" } },
1989 { INDEX_op_shl_i32
, { "r", "r", "ri" } },
1990 { INDEX_op_shr_i32
, { "r", "r", "ri" } },
1991 { INDEX_op_sar_i32
, { "r", "r", "ri" } },
1992 { INDEX_op_rotl_i32
, { "r", "r", "ri" } },
1993 { INDEX_op_rotr_i32
, { "r", "r", "ri" } },
1995 { INDEX_op_brcond_i32
, { "r", "rIN" } },
1996 { INDEX_op_setcond_i32
, { "r", "r", "rIN" } },
1997 { INDEX_op_movcond_i32
, { "r", "r", "rIN", "rIK", "0" } },
1999 { INDEX_op_add2_i32
, { "r", "r", "r", "r", "rIN", "rIK" } },
2000 { INDEX_op_sub2_i32
, { "r", "r", "rI", "rI", "rIN", "rIK" } },
2001 { INDEX_op_brcond2_i32
, { "r", "r", "rIN", "rIN" } },
2002 { INDEX_op_setcond2_i32
, { "r", "r", "r", "rIN", "rIN" } },
2004 #if TARGET_LONG_BITS == 32
2005 { INDEX_op_qemu_ld8u
, { "r", "l" } },
2006 { INDEX_op_qemu_ld8s
, { "r", "l" } },
2007 { INDEX_op_qemu_ld16u
, { "r", "l" } },
2008 { INDEX_op_qemu_ld16s
, { "r", "l" } },
2009 { INDEX_op_qemu_ld32
, { "r", "l" } },
2010 { INDEX_op_qemu_ld64
, { "L", "L", "l" } },
2012 { INDEX_op_qemu_st8
, { "s", "s" } },
2013 { INDEX_op_qemu_st16
, { "s", "s" } },
2014 { INDEX_op_qemu_st32
, { "s", "s" } },
2015 { INDEX_op_qemu_st64
, { "s", "s", "s" } },
2017 { INDEX_op_qemu_ld8u
, { "r", "l", "l" } },
2018 { INDEX_op_qemu_ld8s
, { "r", "l", "l" } },
2019 { INDEX_op_qemu_ld16u
, { "r", "l", "l" } },
2020 { INDEX_op_qemu_ld16s
, { "r", "l", "l" } },
2021 { INDEX_op_qemu_ld32
, { "r", "l", "l" } },
2022 { INDEX_op_qemu_ld64
, { "L", "L", "l", "l" } },
2024 { INDEX_op_qemu_st8
, { "s", "s", "s" } },
2025 { INDEX_op_qemu_st16
, { "s", "s", "s" } },
2026 { INDEX_op_qemu_st32
, { "s", "s", "s" } },
2027 { INDEX_op_qemu_st64
, { "s", "s", "s", "s" } },
2030 { INDEX_op_bswap16_i32
, { "r", "r" } },
2031 { INDEX_op_bswap32_i32
, { "r", "r" } },
2033 { INDEX_op_ext8s_i32
, { "r", "r" } },
2034 { INDEX_op_ext16s_i32
, { "r", "r" } },
2035 { INDEX_op_ext16u_i32
, { "r", "r" } },
2037 { INDEX_op_deposit_i32
, { "r", "0", "rZ" } },
2039 { INDEX_op_div_i32
, { "r", "r", "r" } },
2040 { INDEX_op_divu_i32
, { "r", "r", "r" } },
2045 static void tcg_target_init(TCGContext
*s
)
2047 #if defined(CONFIG_GETAUXVAL) && !defined(use_idiv_instructions)
2049 unsigned long hwcap
= getauxval(AT_HWCAP
);
2050 use_idiv_instructions
= (hwcap
& HWCAP_ARM_IDIVA
) != 0;
2054 tcg_regset_set32(tcg_target_available_regs
[TCG_TYPE_I32
], 0, 0xffff);
2055 tcg_regset_set32(tcg_target_call_clobber_regs
, 0,
2060 (1 << TCG_REG_R12
) |
2061 (1 << TCG_REG_R14
));
2063 tcg_regset_clear(s
->reserved_regs
);
2064 tcg_regset_set_reg(s
->reserved_regs
, TCG_REG_CALL_STACK
);
2065 tcg_regset_set_reg(s
->reserved_regs
, TCG_REG_TMP
);
2066 tcg_regset_set_reg(s
->reserved_regs
, TCG_REG_PC
);
2068 tcg_add_target_add_op_defs(arm_op_defs
);
2071 static inline void tcg_out_ld(TCGContext
*s
, TCGType type
, TCGReg arg
,
2072 TCGReg arg1
, tcg_target_long arg2
)
2074 tcg_out_ld32u(s
, COND_AL
, arg
, arg1
, arg2
);
2077 static inline void tcg_out_st(TCGContext
*s
, TCGType type
, TCGReg arg
,
2078 TCGReg arg1
, tcg_target_long arg2
)
2080 tcg_out_st32(s
, COND_AL
, arg
, arg1
, arg2
);
2083 static inline void tcg_out_mov(TCGContext
*s
, TCGType type
,
2084 TCGReg ret
, TCGReg arg
)
2086 tcg_out_dat_reg(s
, COND_AL
, ARITH_MOV
, ret
, 0, arg
, SHIFT_IMM_LSL(0));
2089 static inline void tcg_out_movi(TCGContext
*s
, TCGType type
,
2090 TCGReg ret
, tcg_target_long arg
)
2092 tcg_out_movi32(s
, COND_AL
, ret
, arg
);
2095 static void tcg_target_qemu_prologue(TCGContext
*s
)
2099 /* Calling convention requires us to save r4-r11 and lr. */
2100 /* stmdb sp!, { r4 - r11, lr } */
2101 tcg_out32(s
, (COND_AL
<< 28) | 0x092d4ff0);
2103 /* Allocate the local stack frame. */
2104 frame_size
= TCG_STATIC_CALL_ARGS_SIZE
;
2105 frame_size
+= CPU_TEMP_BUF_NLONGS
* sizeof(long);
2106 /* We saved an odd number of registers above; keep an 8 aligned stack. */
2107 frame_size
= ((frame_size
+ TCG_TARGET_STACK_ALIGN
- 1)
2108 & -TCG_TARGET_STACK_ALIGN
) + 4;
2110 tcg_out_dat_rI(s
, COND_AL
, ARITH_SUB
, TCG_REG_CALL_STACK
,
2111 TCG_REG_CALL_STACK
, frame_size
, 1);
2112 tcg_set_frame(s
, TCG_REG_CALL_STACK
, TCG_STATIC_CALL_ARGS_SIZE
,
2113 CPU_TEMP_BUF_NLONGS
* sizeof(long));
2115 tcg_out_mov(s
, TCG_TYPE_PTR
, TCG_AREG0
, tcg_target_call_iarg_regs
[0]);
2117 tcg_out_bx(s
, COND_AL
, tcg_target_call_iarg_regs
[1]);
2118 tb_ret_addr
= s
->code_ptr
;
2120 /* Epilogue. We branch here via tb_ret_addr. */
2121 tcg_out_dat_rI(s
, COND_AL
, ARITH_ADD
, TCG_REG_CALL_STACK
,
2122 TCG_REG_CALL_STACK
, frame_size
, 1);
2124 /* ldmia sp!, { r4 - r11, pc } */
2125 tcg_out32(s
, (COND_AL
<< 28) | 0x08bd8ff0);